POJ 1011 Sticks(深搜+强剪枝)

题意:给你很多短的棒子,它们的长度告诉你,它们是由很多根长的棒子截出来的,问你这些短的棒子可以组成很多个相等的长棒子,求单个长棒子最短是多少?

想法:设所有棒子的总长为sum,seglen为单个长棒子的长度。通过题意,你需要知道当前seglen还有多少?sum还有多少可以用。

剪枝:1.seglen必定不小于所有短木棒里面最长的那个。

          2.seglen的长度肯定能被sum整除。

          3.长度数组从大到小排序。

          4.如果剩下的剪枝~在程序里……

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,slen[70];
int sum,seg_len;
int vis[70];
bool cmp(int x,int y)
{
	return x>y;
} 
void Input()
{
	sum=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&slen[i]);
		sum+=slen[i];
	}
}
int dfs(int pos,int seglen,int restlen)
{
	if(restlen==seglen) return 1;//余下的总长度等于余下的一段的长度 
	if(restlen==seg_len) return 1;//余下的总的长度等于要求的一段总长度 
	for(int i=pos;i<=n;i++)
	{
		if(vis[i]||slen[i]>seglen) continue;
		vis[i]=1;
		if(seglen==slen[i])//KEY1
		{
			if(dfs(1,seg_len,restlen-slen[i])) return 1;
		}
		else if(dfs(i+1,seglen-slen[i],restlen-slen[i])) return 1;
		vis[i]=0;
		if(seglen==slen[i]) return 0;//对KEY1第一个if的判定 
		if(restlen==sum) return 0;//对第一次的进行剪枝
		if(seglen==seg_len) return 0;//对KEY1第二个if的判定 
	    while(slen[i]==slen[i+1]) i++;//一样的没有必要再取了 
	}
	return 0;
} 
void treatment()
{
	sort(slen+1,slen+1+n,cmp);
	memset(vis,0,sizeof(vis));
	for(int i=n;i>=1;i--)
	{
		if(sum%i==0&&sum/i>=slen[1])
		{
			seg_len=sum/i;
			if(dfs(1,seg_len,sum)) break;
		}
	}
	printf("%d\n",seg_len);
}
int main()
{
	while(~scanf("%d",&n),n)
	{
		Input();
		treatment();
	}	
	return 0;
}


你可能感兴趣的:(搜索)