搜索剪枝
1.枚举范围maxa~sum/2。从小到大枚举原木棍长度,有合法答案直接break;
2.从大到小排序a数组
5.预处理nxt数组,直接跳过重复元素
4.当前长度为now时,二分找下一个不大于x-now的木棍
5.now为0或者now+a[i]==x时失败了,直接return 0;
6.dfs参数添加lst加速二分速度(
AC代码:
#include<bits/stdc++.h>
//#define int long long
using namespace std;
int m,n,a[70],sum,ans;
int b[70];
int nxt[70];
bool cmp(int x,int y){
return x>y;
}
bool dfs(int x,int now,int cnt,int lst){
if(x*cnt==sum&&x<ans){
ans=x;
return 1;
}
int pos=lower_bound(a+lst+1,a+n,x-now,cmp)-a;
for(int i=pos;i<n;i++){
if(!b[i]){
if(now+a[i]==x){
b[i]=1;
if(dfs(x,0,cnt+1,-1)){
b[i]=0;
return 1;
}
else{
b[i]=0;
return 0;
}
}
else if(now+a[i]<x){
b[i]=1;
if(dfs(x,now+a[i],cnt,i)){
b[i]=0;
return 1;
}
else{
b[i]=0;
if(now==0)return 0;
i=nxt[i]-1;
}
}
}
}
return 0;
}
signed main(){
//freopen("D:\\c++\\data.in","r",stdin);
scanf("%d",&m);
int maxa=0,tmp;
for(int i=0;i<m;i++){
scanf("%d",&tmp);
if(tmp>50){
continue;
}
a[n]=tmp;
sum+=a[n++];
maxa=max(maxa,a[i]);
}
ans=sum;
sort(a,a+n,cmp);
nxt[n-1]=n;
for(int i=n-2;i>=0;i--){
if(a[i]==a[i+1])nxt[i]=nxt[i+1];
else{
nxt[i]=i+1;
}
}
for(int i=maxa;i<=sum/2+1;i++){
if(sum%i==0){
if(dfs(i,0,0,-1))break;
}
}
cout<<ans<<endl;
return 0;
}