POJ 1011 Sticks(dfs)

Description
乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示
Input
多组输入,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。以0结束输入
Output
对于每组数据,分别输出原始木棒的可能最小长度,每组数据占一行
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5
Solution
剪枝+dfs
几个重要剪枝
1.越长的木棍对后面木棍的约束力越大,因此要把小木棍排序,按木棍长度从大到小搜索,这样就能在尽可能靠近根的地方剪枝。
2.当出现加上某根木棍恰好能填满一根原始木棍,但由在后面的搜索中失败了,就不必考虑其他木棍了,直接退出当前的枚举。
3.考虑每根原始木棍的第一根木棍,如果当前枚举的木棍长度无法得出合法解,就不必考虑下一根木棍了,当前木棍一定是作为某根原始木棍的第一根木棍的,现在不行,以后也不可能得出合法解。也就是说每根原始木棍的第一根小木棍一定要成功,否则就返回。
4.跳过重复长度的木棍,当前木棍跟它后面木棍的无法得出合法解,后面跟它一样长度的木棍也不可能得到合法解,因为后面相同长度木棍能做到的,前面这根木棍也能做到。
Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
using namespace std;
#define maxn 65

int n,sum,goal;//n表示木棍数量,sum表示木棍总长 ,goal表示目标棒长 
int stick[maxn];//木棍长度 
bool visit[maxn];//标记数组 

bool cmp(const int &a,const int &b)
{
    return a>b;
}

bool dfs(int now,int index,int cnt)//now表示正在组合的木棒长度,index表示已经用到第几根木棒,cnt表示组合成功的木棒数 
{
    if(goal*cnt==sum)//所有木棒组合成功,返回true 
        return true;
    for(int i=index;i<n;i++) 
    {
        if(visit[i]||(i&&!visit[i-1]&&stick[i]==stick[i-1]))//如果此木棍已被使用或者在前面的搜索中与其长度相同的木棍不满足条件未被使用则跳过 
            continue;
        if(now+stick[i]==goal)//当前木棒组合成功 
        {
            visit[i]=true;//该木棍被使用 
            if(dfs(0,0,cnt+1))//得到合法解,返回true 
                return true;
            visit[i]=false;//回溯 
            return false;//没有得到合法解,返回false 
        }
        else if(now+stick[i]<goal)//加上此段木棍长度 
        {
            visit[i]=true;//该木棍被使用 
            if(dfs(now+stick[i],i+1,cnt))//得到合法解,返回true 
                return true;
            visit[i]=false;//回溯 
            if(now==0)//正在组合的木棒的第一根木棍已经无法得到合法解,返回false 
                return false;
        }
    } 
    return false;//枚举所有木棍没有得到合法解,返回false 
}

int solve()
{
    sort(stick,stick+n,cmp);//对木棍降序排列 
    for(goal=stick[0];goal<=sum;goal++)//目标木棒长度必然不小于最长的木棍 
    {
        if(sum%goal!=0)//目标木棒长度不能整除总长,不满足条件 
            continue;
        memset(visit,false,sizeof(visit));//初始化 
        if(dfs(0,0,0))//返回可行解 
            return goal;
    }
}

int main()
{
    while(scanf("%d",&n))
    {
        if(!n) 
            break;
        sum=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&stick[i]);
            sum+=stick[i];//木棒总长 
        }
        printf("%d\n",solve());
    }
    return 0;
}

你可能感兴趣的:(POJ 1011 Sticks(dfs))