要理解剪枝3和4,重点在于理解它是从哪里剪掉的。对于3,设失败的第一个小木棒为x,剪掉说明上一层的这里 if(part==length) return dfs(u+1,0,0);返回false.然后就会退回到上一根木棒的最后一个,由于4,再退回到上一个,也就是清除了上一根木棒的最后两个小木棍,然后从这里重新枚举其他可能。但是没有这个剪枝的话,就会从x所在木棍清除x后开始枚举下一根小木棒。如果是这样的话,那么假设成功,x也一定会在某个木棍的第一个,(因为如果有比x更长的木棒在x前面的情况应该更先考虑),那么就导致了矛盾。
剪枝就是什么时候回溯,已经发现了一个不可行,就没有必要枚举下去了。剪枝3,
第一根棒失败了,实际是前面的组合需要修改,或该长度压根不行。不改前面的后面的枚举就都没有意义,因此需要进行剪枝。剪枝4,最后一根失败了,实际上就要从这里开始回溯。
`#include[HTML_REMOVED]
include[HTML_REMOVED]
include[HTML_REMOVED]
using namespace std;
const int N=64;
int w[N];
int sum,length;
bool st[N];
int n;
bool dfs(int u,int cur,int start)
{
if(u*length==sum)return true;
if(cur==length)dfs(u+1,0,0);
for(int i=start;i[HTML_REMOVED]length)continue;//跳过只是跳过当前棒子
st[i]=true;
if(dfs(u,cur+w[i],i+1))return true;
st[i]=false;
if(!cur||w[i]+cur==length)return false;//return 即是剪枝
int j=i;
while(j<n&&w[j]==w[i])j++;
i=j-1;
}
return false;
}
int main()
{
while(cin>>n,n)
{
memset(st,0,sizeof st);//每组数据处理之前要重置st
sum=0;
for(int i=0;i[HTML_REMOVED]>w[i];
sum+=w[i];
}
sort(w,w+n);
reverse(w,w+n);
length=1;
while(true)
{
if(sum%length==0&&dfs(0,0,0))
{
cout<<length<<endl;
break;
}
length++;
}
}
return 0;
}
`