HDU 1455Sticks 解题报告

来源:互联网 发布:bootstrap.js下载 编辑:程序博客网 时间:2024/05/19 23:25



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

95 2 1 5 2 1 5 2 141 2 3 40

Sample Output

65




       DFS搜索。

       很好的剪枝范例。

       由一堆长度(可能)不等的小木条,拼接出几组长度相等的新木条,要求这些长度相等的新木条的长度尽可能小。


       显然,所有拼接方案中,新木条长度最小的方案,即取原木条中最长木条的长度为新木条的长度。当然,这种方案不一定可行,但是不会存在新木条长度比这种方案更小的可能。

       同时,所有拼接方案中,新木条长度最大的方案,即是将所有原木条拼成一根新木条,这时新木条数量只有一根,长度是所有原木条长度之和。显然,不会存在新木条长度比这种方案还大的可能。这种拼法一定可行,但不一定是最优解。

       所以,最优解的新木条长度,一定在最长的原木条的长度与所有原木条的长度的和之间。

       还要注意的是,拼出的几根新木条长度相等,意味着任一可行方案中,所有原木条的长度之和,一定是新木条长度的整数倍。而这个倍数,即为这种方案中,新木条的数目。


       我们在拼接的时候,采取一组一组拼的方式。这一组原木条拼出了一个目标长度,我们便再从剩下的原木条中继续尝试拼接。直到所有的原木条都拼接完毕,即拼接出的组数与预定方案的新木条数目相等为止。在拼接的过程中,我们采取从长到短的顺序搜索。取剩下的原木条中尽可能大的木条,与当前组的木条尝试拼接。显然这里有点贪心的味道。当然不一定就能一次拼好,要不断的通过递归进行调整。

       

       关于这道题的剪枝,其实也有点贪心的味道。举个例子,现在一个完整的木条A,差一定长度可达到目标的新木条长度。如果所差的长度,既可以用一根较长的木条B直接补齐,也可以用几根长度较短的木条一起凑出的话,那么优先考虑用木条B来拼。因为在与其他木条拼接的过程中,几根较短的木条会比较长的木条更灵活,更有可能拼接成功。换句话说,在这种情况下,如果我们已经选择了使用木条B来与木条A拼接构成了一个目标的新木条长度,但是剩下的木条仍然不能全部拼接成功的话,就意味着木条A与其他剩下的原木条一定无法拼出目标长度了。而在实际过程中,如果上述的“木条A”是由几个更小的木条拼出来的,就意味着前面拼凑出“木条A”的流程是错的,要利用递归倒回去调整。而如果木条A就是一根完整的原木条,就意味着之前几组木条的拼接有问题,要倒回去调整。这一结论用于剪枝。




#include <iostream>#include <algorithm>using namespace std;int sti[70];int used[70];int len,num,sum,n;int cmp(int a,int b){    return a>b;}int dfs(int pos,int l,int fini){    if(fini==num)        return true;    for(int i=pos;i<n;i++)    {        if(used[i])            continue;        if(l+sti[i]==len)        {            used[i]=1;            if(dfs(0,0,fini+1))                return 1;            used[i]=0;            return 0;//剪枝        }else if (l+sti[i]<len)        {            used[i]=1;            if(dfs(i+1, l+sti[i], fini))                return 1;            used[i]=0;            if(l==0)                return 0;//剪枝            while(sti[i]==sti[i+1])                i++;//剪枝        }    }    return 0;}int main(){    while(~scanf("%d",&n)&&n)    {        sum=0;        for(int i=0;i<n;i++)        {            scanf("%d",&sti[i]);            used[i]=0;            sum+=sti[i];        }        sort(sti, sti+n, cmp);        for(len=sti[0];len<sum;len++)        {            if(sum%len)                continue;            //将非法情况continue,否则求num的计算会出问题            num=sum/len;            if(dfs(0, 0, 0))                break;        }        printf("%d\n",len);    }    return 0;}











0 0