Sticks (剪枝)

本文探讨了如何使用深度优先搜索(DFS)结合剪枝技术来解决复杂问题。作者分享了两种不同的实现方式,其中一种是个人原创,另一种是从网络上获取的灵感。在第二種方法中,特别提到了在求和为0的情况下的讨论对于避免超时至关重要。
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
Output
The output should contains the smallest possible length of original sticks, one per line.
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6

5

问题分析:深搜+剪枝剪枝剪枝!!!已在代码中标注

第一种自己写的:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;

int vis[70];
int stick[70];
int len,flag,sum,n,s,pre;

int cmp(int a,int b)
{
	return a>b;
}

void dfs(int length,int num)
{
	if (num==0)
	{
		flag = 1;
		return ;
	}
	
	for(int i=0; i<n; i++)
	{
		if (vis[i]==0)
		{
			if (length+stick[i]<=len)
			{
				length += stick[i];
				vis[i] = 1;
				if (length==len)	dfs(0,num-1);
				else				dfs(length,num-1);
				if (flag)			return ;
				length -= stick[i];
				vis[i] = 0; 
				if (length==0)
					return ;
				if (stick[i]==stick[i+1])
				{
					while(stick[i]==stick[i+1] && i+1<n)
						i++;
				}
			}		
		}
	}
}

int main()
{
	while(~scanf("%d", &n))
	{
		if (n==0)
			return 0;
		
		s = 0;
		for(int i=0; i<n; i++)
		{
			scanf("%d",&stick[i]);
			s += stick[i];
		}
		
		sort(stick,stick+n,cmp);
		memset(vis,0,sizeof(vis));
		flag = 0;
		for(len = stick[0]; len<=s; len++)
		{
			if (s%len)
				continue;
			
			dfs(0,n);
			if (flag)	break;
		}
		printf("%d\n",len); 
	}
	return 0;
}


第二种写法:这里是参考网上的,没想懂在sum=0是为啥要单独讨论,不讨论就会超时

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;

int slen[70];
int total;
int book[70];
int len;
int flag;
int n;

int cmp(int a,int b)
{
	return a>b;
}

void dfs(int t,int m,int sum)	//t是用掉的小棒数量,m是接下来要摆放的小棒,sum为当前长度 
{
	if (sum == 0)
	{
		int cur = 0;
		while(book[cur])	cur++;
		book[cur] = 1;
		dfs(t+1,cur+1,slen[cur]);
		book[cur] = 0;
		return ;	
	}  
	//如果当前长度已经达到枚举长度 
	if (sum == len)
	{
		//如果小棒数量已经用完了
		if (t == n) 
			flag = 1;
		//小棒没有用完 
		else
			dfs(t,0,0);
		return ;
	}
	 
	for(int i=m; i<n; i++)
	{
		if (book[i] == 0 && sum + slen[i] <= len)
		{
			
			//如果这一根与上一根相同并且上一根没有选,那么这一根也不选 
			if (book[i-1] == 0 && slen[i] == slen[i-1])
				continue;
			book[i] = 1;
			dfs(t+1,i+1,sum+slen[i]);
			book[i] = 0;
			//如果该小棒不能搭配,那么之后相同长度的小棒都不行 
			while(slen[i] == slen[i+1])	i++;
			if (flag)
				return ;
		
		}
	}
}

int main()
{
	while(~scanf("%d",&n))
	{
		if (n == 0)
			return 0;		
		
		total = 0;
		for(int i=0; i<n; i++)
		{
			scanf("%d",&slen[i]);
			total += slen[i];
		}
		sort(slen,slen+n,cmp);
		for(len=slen[0]; len<=total; len++)
		{
			if (total % len == 0)	//一定要是因数才能平分,否则大棍长度不可能相等
			{
				memset(book,0,sizeof(book));
				flag = 0;
				dfs(0,0,0);
				if (flag)
				{
					printf("%d\n",len);
					break;
				}	
			}		
		}	
	}			
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值