做完这题后 再也不敢说自己会搜索会剪枝了
剪枝思路见代码注释
使用的方法
1 优化搜索顺序
2 排除等效冗余(主要)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int sum,cnt,len;
int a[70];
bool vis[70];
//x表示正在拼第x根 cab是目前拼成的长度 last的剪枝作用见下面
bool dfs(int x,int cab,int last)
{
if(x>cnt)return true;
//cnt根木棒匹配成功
if(cab==len)return dfs(x+1,0,1);
//这一根已经匹配完了
int fail=0;
//统计 如果长度为fail的失败了其他长度为fail的就不用试了
for(int i=last;i<=n;++i)
//last:按照一定的次序组成,不会影响结果
{
if(!vis[i]&&a[i]+cab<=len&&a[i]!=fail)
{
vis[i]=true;
if(dfs(x,cab+a[i],i+1))return true;
vis[i]=false;
fail=a[i];
if(cab==0||cab+a[i]==len)return false;
//对于cab==0来说a[i]是空木棍第一个组成的部分 a[i]既然放在此处不可放到后面的其他空木棍也不可
//cab+a[i]==len可以用贪心来解释 此处用一根来与cab组成len比往后再找k根和为a[i]的更优
}
}
return false;
}
int main()
{
while(scanf("%d",&n)&&n)
{
sum=0;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a+1,a+n+1);
reverse(a+1,a+n+1);
//从大到小排序 减小搜索树规模
for(len=a[1];len<=sum;++len)
{
if(sum%len)continue;
memset(vis,0,sizeof(vis));
cnt=sum/len;
if(dfs(1,0,1))break;
}
printf("%d\n",len);
}
return 0;
}