dfs搜索+剪枝

C - 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 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

题解:dfs搜索,但需要很多剪枝,比如说相同的木条就不用再搜索等等。。。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=65;
int used[maxn],stick[maxn];
int n,sum,num,l;
bool cmp(int a,int b)
{
    return a>b;
}
bool dfs(int s,int le,int pos)//s表示已经拼好了几根木棒,le表示将要用来拼接的小木条长度,pos表示当前搜索的位置(下标)
{
    if(s==num) return true;
    int sign=le==0?1:0;//记录是否没有木条了
    for(int i=pos+1;i<n;i++)
    {
        if(used[i]) continue;//如果改木条被用过则跳过
        if(le+stick[i]==l)//如果刚好能够拼接成一根木棒进行下一根木棒的拼接
        {
            used[i]=1;//置为已使用
            if(dfs(s+1,0,-1))//下一根木棒也能拼接成功说明l为答案
                return true;
            used[i]=0;//如果本次搜索失败应还原used
            return false;//下一次不能够拼成则失败了
        }
        else if(le+stick[i]<l)//如果小于则接着往下搜
        {
            used[i]=1;
            if(dfs(s,le+stick[i],i))
              return true;
            used[i]=0;
            if(sign) return false;//表示没有木条可拼接了意味着失败了(不能直接return false,假如还有木条还可继续拼接)
            while(stick[i]==stick[i+1]) i++;//如果木条长度相同不必再搜索
        }
    }
    return false;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    while(cin>>n&&n)
    {
    sum=0;
    for(int i=0;i<n;i++)
    {
        cin>>stick[i];
        sum+=stick[i];
    }
    sort(stick,stick+n,cmp);//把木条从大到小排列
    int ans;
    for(l=stick[0];l<=sum;l++)
    {
        if(sum%l==0)
        {
            memset(used,0,sizeof used);//每种l都应该重置used
            num=sum/l;//该情况下应该有的木棒数
            if(dfs(0,0,-1))
            {
                ans=l;
                break;
            }
        }
    }
    cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shaohang_/article/details/81068299
今日推荐