POJ 1011 sticks DFS+剪枝

来源:互联网 发布:淘宝上卖工艺品好卖吗 编辑:程序博客网 时间:2024/05/29 14:43
G - Sticks
Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%lld & %llu
Submit Status

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

95 2 1 5 2 1 5 2 141 2 3 40

Sample Output

65
题意:给出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;}

  
0 0