Sticks

来源:互联网 发布:小学英语教学软件 编辑:程序博客网 时间:2024/06/05 20:27

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

6

5

又是一道浪费了我好几个小时的题,被这条if(sum%len==0 && DFS(0,len,sum)) 坑死了,一直在调BUG,这道最经典的

深搜实在是经典啊。 

1:这道题为什么是从大到小排序呢?因为这样可以更早结束深搜,可能这样说比较难理解,我举个例子假设木棍长度如下:10 9

4 8 3 那么我们是从10开始搜索好呢还是从3开始搜索好呢?因为原始木棍的最短长度就是10,那么如果我们从3开始,得搜三次

才能确定10不行,但如果从10开始,那么只需搜两次,也就是说,我们可以更早的发现当前最短长度是不行的,减少搜索次数。

2:len的长度最大是sum/2,这个剪枝很好理解。

3:这是最坑点啊,我被这个坑点坑的怀疑人生,就是先判断sun%len==0 啊还是先DFS,傻子都知道不能先DFS,这个点在以后做搜索题目时要时时谨记。

4:再说说我这道题我自己独特的错误,我把函数参数与全局变量冲了,我靠,昨天我好想也犯了类似变量命名的错误,这种错误很难发现,又很折磨人。

5:这道题加深了我对于return的理解,return是到调用它的函数,而不是直接返回main函数中。

6:说了这么多,其实最重要的还是对于这道题的解法的领悟,为什么这道题要用深搜解决?里边if语句的判断才是深搜的精髓。

#include<stdio.h>#include<iostream>#include<string.h>#include<stdlib.h>#include<algorithm>using namespace std;/*int comp(const void *a,const void *b){return *(int *)b- *(int *)a;}*/int cmp(const int a, const int b) {return a > b;}int n,len;int a[65],flag[65];int DFS(int pos,int l,int s){//if(pos>n) return 0;int i,j;if(l==0)  //说明有一根原始木棍被拼揍成功,接下来拼凑下一根; {s-=len;if(s==0) return 1;for(i=0;flag[i];i++) ;  //得再接着找木棍拼凑flag[i]=1; //选择了下标为i的木棍if(DFS(i+1,len-a[i],s)) return 1; //如果接下来的搜索成功,说明可以全部拼凑成功s+=len; //能走到这一步,说明接下来的搜索没成功 flag[i]=0;return 0; //既然没成功,那么就说明初始长度为这个len不能拼凑成功,换下一个len }else //还得接着凑成完整一根 {for(i=pos;i<n;i++) //接着在剩余的棒子中找 {if(i>0 && a[i]==a[i-1] && flag[i-1]==0) //这个剪枝很重要,就是我在凑棍子的时候,如果我之前那根不行,那么后边和他长度//相同的棍子肯定也不行,听说这个剪枝使原来的TLE一下变成16MS,看来hack点就在这啊。 {continue; } if(a[i]<=l && !flag[i]) //首先得保证目前找的这根棍子不能比还需凑得长度要大,另外这根棍子得之前没有被选过 {flag[i]=1;l-=a[i];if(DFS(i+1,l,s)) return 1;flag[i]=0;l+=a[i]; } }  return 0; //如果找遍所有棍子都无法凑成原始长度,那么返回0; }}int main(){int i,j,sum=0,tap;while(~scanf("%d",&n) && n){sum=0;tap=0;for(i=0;i<n;i++){scanf("%d",&a[i]);sum+=a[i];}//qsort(a,n,sizeof(int),comp);sort(a,a+n,cmp);for(len=a[0];len<=sum/2;len++){memset(flag,0,sizeof(flag));if(sum%len==0 && DFS(0,len,sum))   //我首先得说明这两个判断条件先后顺序的重要性!!!!你如果反了,一直是TLE {tap=1;printf("%d\n",len);break;}}if(!tap) printf("%d\n",sum);}return 0;}


0 0
原创粉丝点击