poj 1011 木棒

来源:互联网 发布:snap 教程 linux 编辑:程序博客网 时间:2024/06/10 12:25

 此题是一个超级搜索剪枝。

 剪枝的地方:

1.当前这个棍子有没有用过。

2.当他大于所需要搜的长度时,就不用搜了。

3.如果前面一个相等长度的棍子用不上,那么这个棍子自然也用不上。

然后还有一些小剪枝:

4.预处理排序后方便以后搜。

5.从大到小搜,不重复搜。

6.搜的长度一定要整除总长度,而且大于最长的那一根棍子。

7.从当前最长的未被使用的木棍开始搜。

8.设置递归层数。

9.搜索总长度的一半到总长度之间的也无意义。

代码:

 

#include <iostream>
#include <algorithm>
using namespace std;
int sticks[65],n,sum,num,l;
bool mark[65];
bool cmp(int a,int b)
{
    return a>b;
}
bool dfs(int s,int le,int pos)
{
    int i;
    bool sign = (le == 0?true:false);
    if(s==num)return true;
    for(i = pos + 1;i < n;i++)
    {
        if(mark[i])continue;
        if(le + sticks[i]==l)
        {
            mark[i] = true;
            if(dfs(s+1,0,-1))
            return true;
            mark[i] = false;
            return false;
        }
        else if(le + sticks[i]<l)
        {
            mark[i] = true;
            if(dfs(s,le+sticks[i],i))
            return true;
            mark[i] = false;
            if(sign)return false;
            while(sticks[i]==sticks[i+1])i++;
        }
    }
    return false;
}

int main()
{
    while(scanf("%d",&n)!=EOF,n)
    {
        sum = 0;

        for(int i = 0; i < n; i++)
        {
            scanf("%d",&sticks[i]);
            sum += sticks[i];
        }
        sort(sticks,sticks+n,cmp);
        for(l = sticks[0]; l <= sum; l++)
        {
            if(sum%l==0)
            {
                num = sum/l;
                memset(mark,false,sizeof(mark));
                if(dfs(1,0,-1))
                {
                    printf("%d\n",l);
                    break;
                }
            }
        }
    }
    return 0;
}