POJ 1011 sticks DFS+剪枝

44 篇文章 1 订阅
G - Sticks
Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%lld & %llu

Description

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
题意:给出n根小棒的长度stick[i],已知这n根小棒原本由若干根长度相同的长木棒(原棒)分解而来。求出原棒的最小可能长度。
思路:这个题要用到dfs+剪枝,也是我最害怕的一类;
对于这个题,我们可以记录下所有棍子的总和和小棒的最大长度max那么原来的长度一定在max--sum之间, 因为题目中要求求出棒的最
小可能长度,
当然对于特定和长度的木棒,当然是分的根数越多长度越短,所以这里我从大到小枚举棒的可能长度,用dfs求出长度是否可以;
还有:这里我对所有的木棍进行从大到小的排序,个人理解的是我们先从大的开始填补,如果超过就用更小的来补充,留下小的木棒它的
活动范围比较 大,可以去补充不够的那些木棒,而大的木棒有限制;并且如果从大的开始找好处理,并且dfs的时间会比从小的开始要好一点;
关键部分:剪枝
很显然,如果枚举的小木棒的根数不能被和sum整除,那么一定不可能,如果sum/i的到的长度比最大的一根max小的话也一定不可以,
我们直接跳过 没有必要去进行dfs;
从最大的开始dfs如果可以就记录下用过的木棒继续向后dfs,如果不可以就跳过,这里需要注意的是我们dfs里传的是它上一个木棍的
位置,我们每次 只需要从他后面的开始找就好;如果len正好==k 那么长度归0,num++继续查找,如果len<k,len就加上木棒长度,继续dfs;
还有就是如果执行到下面得时候木棒长度还为0,就说明该木棒没有能和他凑起来的,那么就不符合题意,直接返回就好;
如果遇到相同的木棒,没有匹配成功,那么它后面的就没必要匹配了;直接跳过
具体见代码:
   
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int len[200],flag[200];
int n,k,ss,ans;
int cmp(int a,int b)
{  return a>b;
}
void dfs(int now,int finish,int pre){     
      if(finish==ss)
       {   ans=1;
           return ;
	   }
	   if(ans)
	    return ;
	   int i;
	   for(i=pre+1;i<n;i++)
	    {    if(flag[i]) 
	          continue;
	          if(now+len[i]==k)
	          {     flag[i]=1;
	                dfs(0,finish+1,-1);
	                flag[i]=0;
			  }
			  if(now+len[i]<k)
		      {      flag[i]=1;
		             dfs(now+len[i],finish,i);
		             flag[i]=0;
			  }
			  if(now==0)
			   return ;
			  while(len[i]==len[i+1])
			  i++;
			  
		}
		return ;
}
int main(){   
       int sum,max,i;
       while(scanf("%d",&n)!=EOF){
       	if(n==0)
       	break;
       	sum=0;
       	max=0;
       	for(i=0;i<n;i++)
       	{  scanf("%d",&len[i]);
       	   sum+=len[i];
		   }
		   sort(len,len+n,cmp);//从大到小排序,大大减少了递归的次数;
		   max=len[0];
		for(i=n;i>=2;i--){ 
		ans=0;
		if(sum%i) continue;//不能zhen
		      if(sum/i<max)
		         continue;
		      k=sum/i;
		      ss=i;
		      memset(flag,0,sizeof(flag));
		      dfs(0,0,-1);
			  if(ans)
			  break; 
		 }
		 printf("%d\n",sum/i);
		 
	}
	return 0;
}

  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marcus-Bao

万水千山总是情,只给五角行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值