小木棍 爆搜剪枝

小木棍 爆搜剪枝

看了题解,用一个桶记录小木棍(很是机智,反正\(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;
}
posted @ 2019-08-21 23:00  Santiego  阅读(291)  评论(0编辑  收藏  举报