POJ 1011

POJ 1011

Sticks

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 153916   Accepted: 36738

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

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output

6
5

Source

Central Europe 1995

这道题一开始的思路,大概是从假定最终长度为L,所有木棍总长度为SUM,由L开始到SUM,找到SUM可整除的长度len

扫描二维码关注公众号,回复: 2327268 查看本文章

然后使用深搜,将木棍尝试拼接为len。

每次深搜的参数为len,relen,num即尝试拼接的总长度,目前还需要的长度relen),以及目前剩余的木棍数量

例如,

5 2 1 5 2 1 5 2 1

初始化len=6,relen=0,num=9

则开始第一次拼接,把5接入,则下一次深搜参数为len=6,relen-1,num=8

深搜大致分为以下几种情况:

1,如果剩余长度为0且剩余木棍为0,说明整体拼接成功,可返回len

2,  如果剩余长度为0,但剩余木棍不为0,说明拼接成功一次len(子问题成功),此时relen=0

     为了重新开始下一次拼接,len不变,relen变为len,num-1,

3,接下来就是拼接一个len的子问题,

      首先找到未参与拼接的第一个木棍,若其长度小于relen,则说明可以尝试拼接,利用递归,对其进行深搜

      若满足条件1,则直接返回len

      若不满足,则找下一个,

      若最后relen=len或者a[i]==relen,说明在一个拼接len的子问题里面,找不到合适的木棍,

      则直接结束整个深搜,尝试下一个len

 例如: 若木棍为 5 4 3 2 2 2

 sum=18,则6可作为一个len

 len=6,relen=6,num=6

 参与拼接的第一个木棍为5,此时len=6,relen=1,num=5,但是这个参数下的深搜肯定无结果? ? ?

即没有可以与5一起拼为6的木棍,即relen仍然为6=len,此时len=6肯定不满足最后结果,因此直接结束len=6的深搜

又例如:在匹配中

 有5,3,2,1这四个木棒且len=8,

 则在此情况下若5,3拼接之后,其他木棒不能拼接成功,则5,2,1这样的也不会成功,即当a[i]=relen时都不成功,

 则其他情况更不会成功

注意:剪枝问题:除了以上两种例子说的剪枝情况,还有如果有长度相同的木棍,其中一根不能成功,则另一根也不会成功。

          排序问题:首先要对所有木棍进行由大到小的排序,如果最大的那个不成功,其他也没有尝试必要

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std; 
int a[65];
int flag[65];
int n;
bool compare(int a,int b)
{
    return a>b;
}
int dfs(int len,int relen,int num)
{
    if(relen==0&&num==0)//若剩余长度和剩余木棍为0,则整体成功 
    return len;
    if(relen==0)//若剩余长度为0,子问题成功,开始新一轮拼接 
    relen=len;
    for(int i=0;i<n;i++)
    {
         if(flag[i]==1)//跳过已拼接的 
         continue;
         if(a[i]<=relen)
         {
              flag[i]=1;//暂时标记为1 
              if(dfs(len,relen-a[i],num-1))//若整体成功 
              return len;
              flag[i]=0;//否则标记变回0 
              if(relen==len||a[i]==relen)//若遇到剪枝问题1 2,直接跳出,结束 
              break;
              while(a[i+1]==a[i])//若遇到相同长度的,直接跳过 
              i++;
         }
    }
    return 0;
}
int main() 
{
    while(cin>>n&&n!=0) 
    {
        int sum=0,k;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            sum+=a[i];
        }
        sort(a,a+n,compare);
        int max=a[0];
        for(int i=max;i<=sum;i++)
        {
            memset(flag,0,sizeof(flag));//每次重新开始,flag都得初始化为0 
            if(sum%i==0)
            {
                k=dfs(i,0,n);
                if(k)
                break;
            }
        }
        
        cout<<k<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fantastic123/p/9356210.html