poj入门水题--深度搜索(dfs)题 1011,含各种剪枝,比较经典

版权声明:本文为博主原创文章,转载请注明出处,谢谢~ https://blog.csdn.net/qq_17246605/article/details/53872076

深度搜索其实就是递归题,找到递归的条件最重要


1.1011 Sticks

解释:George 闲着无聊把一些长度木棒切成了小的棒子,现在他又想把木棒给复原,但是他不知道有几根棒,每根有多长。现在需要你帮助他复原。

解法:

比较经典的深搜题,里面还涉及到了剪枝还有一点小技巧:

1)因为小的棒子比较容易拼接成大的棒子,所以一开始要把大的放在前面。

2)因为是几根长度相同的,所以原先一根棒子的长度是总长度的约数。

3)因为是原先的棒子切成的,所以后来的一根棒子的长度<=原先棒子的长度。

4)如果拼接的长度大于了原先设定的棒子长度,说明这条路失败,可以剪掉。

上代码:

#include<iostream>
#include<algorithm>
#include<memory.h>
using namespace std;
#define MAX 100
int use[MAX],a[MAX],value,n;//n为棒子根数,sum为所有棒子长度和,value为所要求的最短单根棍子长
int sum;//定义全局变量sum


bool cmp(int a,int b){
	return a>b;
}//使数组a从大到小排列

bool dfs(int i,int left,int total)//试到了第几根,还要多少能拼接成这根木棒,拼接的总长度。
{ 
	int j;
	if(left==0)
	{
		total-=value;//寻找新棒子
		if(total==value)
			return 1;//如果只剩下value长度的没拼接,那么一定是能拼成这个长度的,这是剪枝1。
		if(total<value)
			return 0;//如果剩下的长度小于原先木棒的长度,那么一定拼不成了,可以返回失败了,这是剪枝2。
		for(i=0;i<n;i++)
			if(!use[i])
				break;	
			use[i]=1;//找到第一根没有用过的小木棒,置为用过,去做深搜。
			if(dfs(i+1,value-a[i],total))
				return 1;//成功的话,返回1
			use[i]=0;//不成功的话,重新置为0
			total+=value;//这个value可能不是合适的木棒长度。
			return 0;
	}
	
	else{
		for(j=i;j<n;j++)
		{
			if(a[j]>left||use[j])
				continue;//如果用过或者大于剩余长度,略过,此为剪枝3.
			if((a[j]==a[j-1])&&!use[j-1])
				continue;//如果前一根和后一根相等,且前一根没有用,那么表示这个长度之前就失败了,这次可以不要去深搜了,此为剪枝4.
			use[j]=1;					
			if(dfs(j+1,left-a[j],total))
				return 1;
			use[j]=0;				
		}
		return 0;
		
	}	
	return 0;
}








int searchfactor(int a[],int n){
int k=0;//k是判断是否找到了小于sum的因子
for(value=a[0];value<=sum/2;value++)
{
if(sum%value!=0)//若时间超了,去掉=
continue;
k=dfs(0,value,sum);
if(k!=0)
return value;

  }
  
	if(k==0)
	return sum;//若循环后没有则输出sum
}


int main()
{
	int i;
	while((scanf("%d",&n)!=EOF)&&n)
	{
		memset(use,0,sizeof(use));
		sum=0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			sum+=a[i];
		}
		sort(a,a+n,cmp);
			printf("%d\n",searchfactor(a,n));
	}
	return 0;
}









展开阅读全文

没有更多推荐了,返回首页