1. 程式人生 > >poj1011 木棒 dfs+剪枝

poj1011 木棒 dfs+剪枝

目描述

喬治拿來一組等長的木棒,將它們隨機地砍斷,使得每一節木棍的長度都不超過50個長度單位。然後他又想把這些木棍恢復到為裁截前的狀態,但忘記了初始時有多少木棒以及木棒的初始長度。請你設計一個程式,幫助喬治計算木棒的可能最小長度。每一節木棍的長度都用大於零的整數表示。

Input

輸入包含多組資料,每組資料包括兩行。第一行是一個不超過64的整數,表示砍斷之後共有多少節木棍。第二行是截斷以後,所得到的各節木棍的長度。在最後一組資料之後,是一個零。

Output

為每組資料,分別輸出原始木棒的可能最小長度,每組資料佔一行。

Sample Input

9

5 2 1 5 2 1 5 2 1

4

1 2 3 4

0

Sample Output

6

5

做法很顯然....就是dfs,列舉每一個長度來dfs,其他注意事項就在註釋裡面了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[101],f=0,num,used[101];
int dfs(int N,int now)
{
	if(!now&&!N)return 1;//所有木棒都被選完了 
	if(!now)now=num;//組成了長度為now的一根木棒,開始找下一根木棒 
	for(int i=1;i<=n;i++)
	{
		if(!used[i]&&a[i]<=now)
		{
			if(i>1&&(!used[i-1]&&a[i-1]==a[i]))continue;//如果上一個沒有選且這個個和上一個一樣長那肯定也不選 
			used[i]=1;
			if(dfs(N-1,now-a[i]))return 1;
			else
			{
				used[i]=0;
				if(a[i]==now||now==num)return 0;//如果這一根不選,而且這一根還和剩餘長度一樣長,那麼後面的肯定不能選了。如果這一根不選,而且還沒有選,那麼後面的就選不了了 
			}
		}
	}
	return 0;
}
int main()
{
	int i,j,k;
	while(scanf("%d",&n))
	{
		if(!n)break;
		int s=0,maxl=0;
		for(i=1;i<=n;i++)scanf("%d",&a[i]),s+=a[i];
		sort(a+1,a+1+n,greater<int>());
		for(num=a[1];num<=s/2;num++)//至多s/2的長度,不然就是s了 
		{
			if(s%num==0)//num必定是s因數 
			{
				memset(used,0,sizeof(used));	
				if(dfs(n,num))
				{
					printf("%d\n",num);
					break;
				}
			}
		}
		if(num>s/2)printf("%d\n",s);
	}
	return 0;
}