这是我写过剪枝最多的题目
总计九个剪枝一个优化
最关键的是奇偶性剪枝,可行性剪枝,最优性剪枝
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
int A[70];
bool mark[70];
bool flag;
int n,s,ned;
void dfs(int x,int now,int sum,int jsum){
//剪枝4:找到解后返回
//剪枝5:若找到了ned-1根就直接返回
//剪枝6:若相同,就跳过
//剪枝7:若该木棍长度加上原来长度大于期望长度,直接结束
//剪枝8:类似于剪枝10
//剪枝9:sum为0时该位是必取的
//优化1:从取了的那一位向后循环
if(flag)return;//剪枝4
if(sum==ned-1){flag=1;return;}//剪枝5
if(x>s)return;
if((s&1)&&jsum<ned-sum-1)return;//剪枝8
FOR(i,now,n){
if(mark[i])continue;
if(x+A[i]>s)break;//剪枝7
mark[i]=1;
if(x+A[i]==s)dfs(0,1,sum+1,jsum-(A[i]&1));
else dfs(x+A[i],i+1,sum,jsum-(A[i]&1));
mark[i]=0;
if(!x)return;//剪枝9
while(A[i]==A[i+1])i++;//剪枝6
}
}
int main(){
while(scanf("%d",&n)==1){
if(n==0)break;
int tta=0,jsum=0;
FOR(i,1,n){
scanf("%d",&A[i]);
tta+=A[i];
if(A[i]&1)jsum++;
}
sort(A+1,A+n+1);
//剪枝1:不能整除
//剪枝2:总条数小于期望条数
//剪枝3:若枚举长度为奇数,而奇数个数小于需要个数 则不成立
DOR(i,tta,1){
memset(mark,0,sizeof(mark));
if(tta%i!=0)continue;//剪枝1
flag=0;
s=tta/i,ned=i;
if((s&1)&&(jsum<ned))continue;//剪枝3
if(i>n)continue;//剪枝2
dfs(0,1,0,jsum);
if(flag){
printf("%d\n",s);
break;
}
}
}
return 0;
}