1. 程式人生 > 實用技巧 >P1120 小木棍 [資料加強版]

P1120 小木棍 [資料加強版]

連結Miku

程式碼參考:小藍書

暴力很好寫,可惜過不了,怎麼辦,剪枝起飛。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int len[500001];
int fl[500001];
int sum;
int li;
int cnt;
	int maxx=0;
int ans[500001];
bool dfs(int now,int l,int ord){
	if(now>cnt)//over
	return 1;
	if(l==maxx)
	return dfs(now+1,0,1);//開始下一個 
	int fail=0;
	for(int i=ord;i<=n;++i){
		if(!fl[i]&&l+len[i]<=maxx&&fail!=len[i]){//因為是從大到小放的
		//所以說如果不行的話肯定同樣長度的都不行 
			fl[i]=1;
			if(dfs(now,l+len[i],i+1))
			return 1; 
			fail=len[i];
			fl[i]=0;
			//不好理解的剪枝
			//l==0的部分是因為如果此木棍出現在新木棍中不可行的話,那麼它出現在之後任何一個新木棍的結果都是一樣的--不行
			//後半段同理,貪心的考慮一下,一整根木棍都不行的話,就算用幾根小木棍拼起來也沒有意義 
			if(l==0||l+len[i]==maxx)
			return 0;
			
		}
	}
	return 0;
}
bool cmp(int x,int y){
	return x>y;
}
int main(){     
		scanf("%d",&n);
		sum=0;
	maxx=0;
	int xiu;
	int lll=0;
		for(int i=1;i<=n;++i){
		scanf("%d",&xiu);
		if(xiu>50)//自動忽略 
		continue;
		len[++lll]=xiu;
		sum+=len[lll];
		maxx=max(maxx,len[lll]);
		}
		n=lll;
		sort(len+1,len+n+1,cmp);
		//從大到小搞啊 
		int i;
		for( ;maxx<=sum;++maxx){
			if(sum%maxx) continue;
			//顯然只有原長是總長的因數才有意義 
			cnt=sum/maxx;
			memset(fl,0,sizeof(fl));
			if(dfs(1,0,1)){
			break;
			}
		}
		cout<<maxx<<endl;
	return 0;
}