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

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


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;
}









  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值