UVA-307 Sticks (搜索剪枝)

Description

Download as PDF

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

此题的大致意思就是,给你n跟木棒,让你拼成木棍(木棒-->木棍 ,它俩是有区别滴~~)要尽可能的拼多的木棍,也就是计算拼的木棍的最短长度。

首先,计算出木棒的长度总和。

然后分别将总和除以木棒的个数,(从n到1)这样就得到从小到大排列的可能的木棍长度。

分别对可能的木棍长度进行搜索。最小的可行解即为最终解。

把数据按降序排列。

四次剪枝:

1、不要在同一位置尝试同一根木棒,即如果某根木棒拼不成功,那么跟它相同的木棒都不用继续判断直接跳过。

    假如  5  5  4  4 3  要拼长度为6的木棍是 用5拼不可能成功,那个第二个长度为5的木棒就不用判断了。

2、如果由于以后的拼接失败,需要重新调整第i根棍子的拼法,则不会考虑替换第i根棍子中的第一根木棒(换了也没用)。why?

     因为假设替换后能全部拼成功,那么这被换下来的第一根木棒,必然会出现在以后拼好的某根棍子k中。

3、不要希望通过仅仅替换已拼好棍子的最后一根木棒就能够改变失败的局面。

     因为把已拼好棍子的最后一根木棒替换下来,那么肯定有一个或者两个或者更多拼在一起是最后一根木棒的长度,把它放在后面就好了! 干嘛要替换人家最后一根木棒呢。

4、每次找一根木棒的时候,只要这不是一根棍子的第一条木棒,就不应该从下标为0的木棒开始找,而应该从刚刚(最近)接上去的那条木棒的下一条开始找。

    因为按降序排列的么,上面的都不行,肯定只判断下面的喽!

#include<iostream>
#include<algorithm>
using namespace std;

void sousuo(int,int,int);

bool gg,f[70];
int ans,o,n,i,j,k,a[70];

bool bi(int a,int b){
    return a>b;
}


int main()
{
    while (cin>>n){
        if (n==0) break;
        ans=0;
        for (i=0;i<n;i++){
            cin>>a[i];
            ans+=a[i];
        }
        sort(a,a+n,bi);
        for (i=n;i>=1;i--)
            if (ans%i==0)
            {
                for (j=0;j<n;j++) f[j]=0;
                gg=0;
                o=ans/i;
                sousuo(0,0,n);
                if (gg) break;
            }
        
        cout<<o<<endl;
    }
    
    return 0;    
}

void sousuo(int s,int x,int z){  //s是当前正在找的下标,x是正在配对的数字总和 ,z是未配对的数字个数
    int i;
    if (gg) return;
    if (z==0&&x==0){
        gg=1;
        return;
    }
    
    for (i=s;i<n;i++)
    if (!f[i]&&x+a[i]<=o){
        if (i>0)
        {
            if (!f[i-1]&&a[i]==a[i-1]) continue;    //不要在同一位置尝试同一根木棒
        }
        if (x+a[i]<o){
            f[i]=1;
            sousuo(i+1,x+a[i],z-1);
            f[i]=0;
            if (gg) return;
        }
        else if (x+a[i]==o){
            f[i]=1;
            sousuo(0,0,z-1);
            f[i]=0;
            return;        //不要希望通过仅仅替换已拼好棍子的最后一根木棒就能够改变失败的局面
        }
        if (x==0) return;           //不考虑替换第i根棍子中的第一根木棒
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值