【DFS搜索】poj1011 Sticks

题目描述:给定n个小木棍,将他们接成长度相等的若干根。求接成的木棍长度最小值。

很明显这是一道dfs搜索题。很容易想到所求的值在最长小木棍 和 小木棍总长度 中间。注意不能用二分答案,因为不具有单调性。
只能靠剪枝了。
然而这道题处处都要剪枝才能AC,不愧是经典搜索好题 = =

剪枝一:答案在最长小木棍 和 小木棍总长度 中间,且是总长度的因数。(否则不能接成长度相等的若干根)。
剪枝二:先将小木棍长度从大到小sort一下
在dfs中dfs(int pos,int l,int m) 其中pos表示开始接的位置 ,l表示还需要l的长度使得接成长度相等的木棍,m表示已经接成m根长度相等的木棍了。
若stick[i]==stick[i-1]而used[i-1]=0 此时不需要再算第i根木棍了。
剪枝三:在dfs中 保证stick[i]+l<=len 其中len表示接成木棍的长度
剪枝四:若最长的木棍都不能放入接的序列,那么肯定不能接成了。

身为蒟蒻的我只想到了剪枝一和剪枝三,无限RE。真是见RE君,眼泪掉下来 = =
蒟蒻加油 ↖(^ω^)↗

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

int n ,num[65] ,len ,cnt ,sum;
bool vis[65] ,flag ;

bool dfs(int k,int l,int m)
{
    if(m==cnt)return 1;
    if(l==len)return dfs(0,0,m+1);
    int pre=0;
    for(int i=k;i<n;++i)
    {
        if(!vis[i]&&num[i]!=pre&&num[i]+l<=len) \\ 剪枝二 剪枝三
        {
            pre=num[i];
            vis[i]=1;
            if(dfs(i+1,l+num[i],m))
                return 1;
            vis[i]=0;
            if(k==0)return 0; \\ 剪枝四
        }
    }
    return 0;
}

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

int main()
{
    while(~scanf("%d",&n)&&n)
    {
        sum=0;
        flag=1;

        for(int i=0;i<n;++i)
        {
            scanf("%d",&num[i]);
            sum+=num[i];
        }
        sort(num,num+n,cmp);

        for(len=num[0];len<sum;++len) \\ 剪枝一
            if(sum%len==0)
            {
                cnt=sum/len;
                memset(vis,0,sizeof(vis));
                if(dfs(0,0,0))
                {
                    flag=0;
                    printf("%d\n",len);
                    break;
                }
            }
        if(flag)
            printf("%d\n",sum);
    }
    return 0;
}

你可能感兴趣的:(搜索,DFS,POJ1011)