四种剪枝方式,https://www.bilibili.com/video/av10046345/?p=18 这个老师讲的很清楚了,我不多说了。
附上代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=100;
int a[maxn];
bool flag[maxn];
int n,L,lastst;
bool dfs(int r,int m){
if(r==0&&m==0) return 1;
if(m==0) m=L; //这一根已拼好,拼下一根
int st=(m==L?0:lastst+1);
for(int i=st;i<n;i++){
if(flag[i]==1||a[i]>m) continue;
if(i>0&&flag[i-1]==0&&a[i]==a[i-1]) continue; //不要在同一个地方尝试相同的棍子
flag[i]=true;
lastst=i;
if(dfs(r-1,m-a[i])) return true;
else flag[i]=false; //回溯
if(m==L) return false; //m==L 说明现在拿的是第一根木棒,第一根木棒在这不合适,在其它的地方肯定也不合适
if(a[i]==m) return false; //剪枝,不要尝试替换已经拼好的木棒
}
return 0;
}
int main(){
while(scanf("%d",&n)&&n){
int sum=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n,greater<int>());
bool fff=false;
for(L=a[0];L<=sum/2;L++){
if(sum%L) continue;
memset(flag,0,sizeof(flag));
lastst=0;
if(dfs(n,L)){
fff=true;
break;
}
}
if(fff)
printf("%d\n",L);
else
printf("%d\n",sum);
}
return 0;
}