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 ‘0’.

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段木棒,将他们复原成一些等长的木棒,问复原后最短木棒的长度。

思路:先求出n段木棒的和,并将它从大到小排序,从最长的木棒的长度开始枚举,一直到sum/2。不过这道题需要尽可能多的剪枝。因为复原后每根木棒长度相等,因此木棒的长度肯定能被sum整除,同时,相同长度的木棒尝试一次即可,同时多根相加等于这个长度的都不行。每次去木棒我们还要记录一下取得位置,下一次取直接从下个位置取即可,除非这跟木棒刚好拼成了想要的长度,那就需要从头开始取了。如果枚举的长度都不能拼成,那就只有一种情况了,复原后只有一根,因此长度是sum。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool cmp(int x,int y)
{
    return x>y;
}
int n,l,flag,num[110],book[110];
void dfs(int x,int y,int ll)  //x为剩余木棒的个数,y为此时应从y的位置取木棒,还差ll能把这跟拼好
{
    if(flag)
        return;
    if(x==0&&ll==0)  //木棒全部用完,并且拼成功了
    {
        flag=1;
        return;
    }
    if(ll==0)     //拼成功了一根,此时剩余长度为l
    {
        y=0;
        ll=l;
    }
    for(int i=y;i<n;i++)
    {
        if(!book[i]&&num[i]<=ll)  //这根木棒没有用过,并且长度小于剩余长度
        {
            if(i>0)
            {
                if(!book[i-1]&&num[i-1]==num[i])  //把和它长度一样的过滤掉
                    continue;
            }
            book[i]=1;
            dfs(x-1,i+1,ll-num[i]);  //剩余木棒数减一。把下一下标传过去,剩余长度
            if(flag)
                return;
            book[i]=0;
            if(num[i]==ll||ll==l)   //这个长度的木棒没有拼成,剩余的长度肯定也拼不成了,因为从大到小排的,例如,1+2 就比3更灵活
              return;
        }
    }
    return;
}
int main()
{
    int i,j;
    while(scanf("%d",&n)&&n)
    {
        flag=0;
        int sum=0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&num[i]);
            sum+=num[i];  //求和
        }
        sort(num,num+n,cmp);  //排序
        for(int ll=num[0];ll<=sum/2;ll++)  //枚举每一个长度
        {
            if(sum%ll==0)
            {
                l=ll;  //想要的长度
                memset(book,0,sizeof(book));
                dfs(n,0,ll);
                if(flag)  //找到了
                {
                    printf("%d\n",ll);
                    break;
                }
            }
        }
        if(!flag)//没找到,那就只能是一根了
            printf("%d\n",sum);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41890797/article/details/81155249
今日推荐