此题是一个超级搜索剪枝。
剪枝的地方:
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;
}