(HDU

来源:互联网 发布:八爪鱼导出到数据库 编辑:程序博客网 时间:2024/06/05 21:11

(HDU - 1455)Sticks

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11069 Accepted Submission(s): 3373

Problem 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 file 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根小木棒,现将这些小木棒拼成若干根长度相等的原木棒,问原木棒最小长度是多少。

思路:经典深搜题,关键在于剪枝。设所有木棒的长度之和为sum,能拼成的原木棒长度为len,显然sum要能被len整除。现在枚举len,已知len肯定大于等于最长的那根小木棒,所以只要从maxlen(表示最长的那根木棒)开始枚举,深搜即可。下面对于剪枝进行说明:
将输入的木棒从大到小排序,对dfs参数变量的说明:len——原木棒长度,left——将木棒拼成len长度还需要多少长度的木棒,m——剩余没有被使用的木棒
①相同长度的木棒没必要搜索多次,如果一个不成功,则与他长度相同的木棒也都不会成功
②我们之所以从大到小排序是因为,我们在开始匹配木棒时,总是以大的先开始匹配,如果这个都不能成功,那么比他小的都没有必要进行比较,因为这肯定不能取得全局的成功,而题目又要求要用到所有的木棒
③如果当前木棒不能取得全局的成功,且这个小木棒的长度刚好是left的长度,那么更能说明后面的不能匹配了,因为如此合适的小棒被接收都不能导至试探成功,后面的小棒更不可能,直接返回false。还有就是如果len=left(说明这是新一根原棒,还没有进行匹配),而在预先判断匹配与否时已经判断不能匹配,这样都不能匹配,那么说明以后都不能匹配了,返回false。

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int maxn=70;bool vis[maxn];int a[maxn];int n;bool cmp(int  a,int b){    return a>b;}bool dfs(int len,int left,int m)//len表示原木棒长,left平成len长度的木棒还需要多少长度,m表示剩余没有被用过的木棒个数 {    if(left==0&&m==0) return true;    if(left==0) left=len;    for(int i=0;i<n;i++)    {        if(!vis[i]&&a[i]<=left)        {            if(i)            {                if(!vis[i-1]&&a[i]==a[i-1]) continue;//剪枝,相同长度的木棒一根没有成功,则其他的都不需要搜,肯定也不会成功             }            vis[i]=1;            if(dfs(len,left-a[i],m-1)) return true;            vis[i]=0;            if(a[i]==left||len==left) return false;//关键剪枝步骤,思路见题解思路         }    }    return false;} int main(){    while(~scanf("%d",&n)&&n)    {        int sum=0;        for(int i=0;i<n;i++)        {            scanf("%d",a+i);            sum+=a[i];        }        sort(a,a+n,cmp);        int maxlen=a[0],len;        for(len=maxlen;len<=sum/2;len++)//len>sum/2就只有一种可能就是所有木棒组成一根原木棒        {            memset(vis,0,sizeof(vis));            if(sum%len==0)            {                if(dfs(len,0,n))                 {                    printf("%d\n",len);                    break;                }            }        }        if(len>sum/2) printf("%d\n",sum);    }    return 0;}