poj 1011 Sticks

来源:互联网 发布:抢票软件 编辑:程序博客网 时间:2024/06/05 04:40

Sticks

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 file contains blocks of 2 lines. The first line contains the number of sticks parts after cutting. 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

题意:

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
小木棍的数量<=64

思路:
设木棍的长度为temp,总长为sum。
1.枚举木根长度时:首先sum%temp==0,然后temp>=题目给出的最长的木棍长度。满足这两个条件才可以进入dfs进行深度剪枝搜索。

搜索中的剪枝技巧:

2.将输入的木棍长度从大到小排序,这么做是因为一支长度为 K 的完整木棍,总比几支短的小木棍拼成的要好。
形象一些:
如果我要拼 2 支长为8的木棍,第一支木棍我拼成 5 + 3然后拼第二支木棍但是失败了,而我手中还有长为 2 和 1 的木棍,我可以用 5 + 2 + 1 拼好第一支,再尝试拼第二支,仔细想一想,就会发现这样做没意义,注定要失败的。 我们应该留下 2+1 因为 2+1 比 3 更灵活。

3.相同长度的木棍不要搜索多次。如果第i个棍子不能拼成假设的长度,则和第i个棍子相同长度的棍子也是不可能的,所以可以直接跳过去的!
比如:
我手中有一些木棍, 其中有 2 根长为 4 的木棍, 当前搜索 状态是 5+4+…. (即表示长度为 5,4,2 的三支拼在一起, …表示深层的即将搜索的部分), 进行深搜后不成功,故我没必要用另一个 长度相等的4 再重复进行 5+4+…,这样会多
余。如果没有这步会超时。

4.如果某次拼接选择长度为S 的木棒,导致最终失败,则在同一位置尝试下一根木棒时,要跳过所有长度为S 的木棒。

5.替换第i根棍子的第一根木棒是没用的。
重要剪枝,没有的话超时。
a[i]=cur或rcur=temp时本来表示即将拼成一根棒,或刚进行新一轮拼接(即if中判断的是主问题性质完全相同的子问题)但经过上面的if判断,子问题不能完成所有任务,那么整体不可能完成任务,不再考虑,搜索失败(剪枝)。

代码为:

#include<iostream>#include<cstdio>#include<algorithm>#include<string.h>using namespace std;int a[70],b[70];int sum,n,temp,flag,maxx;int dfs(int cur,int num){   // cout<<"cur "<<cur<<endl;   // cout<<"num "<<num<<endl;   // cout<<"flag "<<flag<<endl;    if(num==0&&cur==0)    {        return 1;    }    if(cur==0)    {        cur=temp;     //   cout<<"curhaha "<<cur<<endl;    }    for(int i=0;i<n;i++)    {        if(a[i]>cur||b[i]==1)            continue;        b[i]=1;       // cout<<"cur "<<cur<<" i "<<a[i]<<endl;        if(dfs(cur-a[i],num-1))            return 1;        b[i]=0;        if(a[i]==cur||cur==temp) /*  最重要,没有的话要超时            a[i]=cur或rcur=temp时本来表示即将拼成一根棒,或刚进行新一轮拼接            (即if中判断的是主问题性质完全相同的子问题)但经过上面的if判断,子问题不能            完成所有任务,那么整体不可能完成任务,不再考虑,搜索失败(剪枝)*/            break;        while(a[i]==a[i+1])            i++;    }    return 0;}bool cmp(int a,int b){    return a>b;}int main(){    while(cin>>n&&n)    {        memset(b,0,sizeof(b));        sum=0,maxx=0;        for(int i=0;i<n;i++)        {            cin>>a[i];            sum+=a[i];            if(a[i]>maxx)                maxx=a[i];        }      //  cout<<sum<<endl;       // cout<<maxx<<endl;       sort(a,a+n,cmp);        for(int i=n;i>=1;i--)        {          //  cout<<i<<endl;            if(sum%i==0&&sum/i>=maxx)            {                temp=sum/i;                flag=i;                memset(b,0,sizeof(b));               /* int k=dfs(temp,n);                cout<<"             k"<<k<<endl;                if(k)                {                    cout<<"         break  "<<endl;                    break;                }*/                if(dfs(temp,n))                {                    break;                }              //  cout<<"flag "<<flag<<endl;            }        }        cout<<temp<<endl;    }}
原创粉丝点击