记录编号 236926 评测结果 AAAAAAAAAA
题目名称 [POJ 1011] 小木棍 最终得分 100
用户昵称 Gravatar6+1 是否通过 通过
代码语言 C++ 运行时间 0.003 s
提交时间 2016-03-15 20:21:43 内存使用 0.32 MiB
显示代码纯文本
#include <iostream>
#include<cstdio>
#include <algorithm>

using namespace std;


int sticks[65];

int used[65];

int n,len;

bool dfs(int i,int l,int t)//i为当前试取的棍子序号,l为要拼成一根完整的棍子还需要的长度,t初值为所有棍子总长度 

{

    if(l==0)

    {

        t-=len;

        

        if(t==0)return true;

        

        for(i=0;used[i];++i);            //剪枝1:搜索下一根大棍子的时候,找到第一个还没有使用的小棍子开始

        

        used[i]=1;                           //由于排序过,找到的第一根肯定最长,也肯定要使用,所以从下一根开始搜索

        if(dfs(i+1,len-sticks[i],t))return true;

        used[i]=0;

            

        t+=len;

    }

    else

    {

        for(int j=i;j<n;++j)

        {

            if(j>0&&(sticks[j]==sticks[j-1]&&!used[j-1]))  //剪枝2:前后两根长度相等时,如果前面那根没被使用,也就是由前面那根

                continue;                                                //开始搜索不到正确结果,那么再从这根开始也肯定搜索不出正确结果,此剪枝威力较大

                                                                                  

            if(!used[j]&&l>=sticks[j])   //剪枝3:最简单的剪枝,要拼成一根大棍子还需要的长度L>=当前小棍子长度,才能选用                           

            {

                l-=sticks[j];

                used[j]=1;

                if(dfs(j,l,t))return true;

                    

                l+=sticks[j];

                used[j]=0;

                

                if(sticks[j]==l)    //剪枝4:威力巨大的剪枝,程序要运行到此处说明往下的搜索失败,若本次的小棍长度刚好填满剩下长度,但是后

                    break;           //面的搜索失败,则应该返回上一层

            }

        }

    }

    return false;

}


bool cmp(const int a, const int b)

{ 

    return a>b; 

}


int main()

{

freopen("sticka.in", "r", stdin);
freopen("sticka.out", "w", stdout);

    cin>>n; 

        int sum=0;

        for(int i=0;i<n;++i)

        {

            cin>>sticks[i];
            if(sticks[i]>50) sticks[i]=0;

            sum+=sticks[i];

            used[i]=0;

        }

        

        sort(sticks,sticks+n,cmp);   //剪枝5:从大到小排序后可大大减少递归次数

        

        bool flag=false;

        for(len=sticks[0];len<=sum/2;++len)   //剪枝6:大棍长度一定是所有小棍长度之和的因数,且最小因数应该不小于小棍中最长的长度

        {

            if(sum%len==0)     

            {

                if(dfs(0,len,sum))

                {

                    flag=true;

                    cout<<len<<endl;

                    break;

                }

            }

        }

        if(!flag)

            cout<<sum<<endl;


    return 0;

}