小木棍 爆搜剪枝
小木棍 爆搜剪枝
看了题解,用一个桶记录小木棍(很是机智,反正\(N\le50\)),然后就是爆搜剪枝了。
主要是注意一个优化思想:每次拼一个木棍时,一定先用大的去填再用小的去补。
递减遍历桶和下面这个最重要的剪枝都是这个优化思想
if(sum+i==per||sum==0) break;
连用大刚好填满这种最优方法都无法拼出,那更不用说先用小的去拼这种方法了。
#include <cstdio>
#include <cstdlib>
#define MAX(A,B) ((A)>(B)?(A):(B))
#define MIN(A,B) ((A)<(B)?(A):(B))
using namespace std;
int n,cnt[55];
int mx=0,mi=75;
void solve(int num, int sum, int per, int s){
if(num==0){
printf("%d\n", per);
exit(0);
}
if(sum==per){
solve(num-1, 0, per, mx);
return;
}
for(register int i=s;i>=mi;--i){
if(cnt[i]==0||i+sum>per) continue;
--cnt[i];
solve(num, sum+i, per, i);
++cnt[i];
if(sum+i==per||sum==0) break;
}
}
int temp,all;
int main(){
scanf("%d", &n);
for(int i=1;i<=n;++i){
scanf("%d", &temp);
++cnt[temp];
all+=temp;
mx=MAX(mx, temp);
mi=MIN(mi, temp);
}
for(int i=mx;i<=all/2;++i){
if(all%i!=0) continue;
solve(all/i, 0, i, mx);
}
printf("%d\n", all);
return 0;
}