POJ 1011 Sticks(搜索 && 剪枝 && 经典)

题意 : 有n根木棍(n<=64),它们由一些相同长度的木棍切割而来,给定这n根木棍的长度,求使得原来长度可能的最小值。

分析 : 很经典的深搜题目,我们发现答案只可能是所有木棍长度总和的因数,那么我们只要去枚举因数然后搜索是否可行即可!具体实现看代码可能更容易看懂,这里不赘述。重要的是体会此类深搜的代码构建过程以及剪枝的考虑的巧妙性!

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 64 + 5;
bool vis[maxn];
int sticks[maxn];
int CurLen;
int n;
int Remain;///每一次都去重置为
bool DFS(int id, int Lack)///传入的参数为上次选择了哪个木棍、当前还缺多少才能组成一个新的目标木棍
{
    if(Lack == 0){///已经组成一个新的木棍了,

        Remain -= CurLen;
        if(Remain == 0) return true;///如果当前总长为0,说明此方案可行!

        int which;
        for(which=0; vis[which]==true; which++);///由于是排好序,我们取第一个没有使用过的木棍开始下一次的搜索

        vis[which] = true;///标记

        if( DFS(which, CurLen-sticks[which]) ) return true;///开始新一轮搜索

        vis[which] = false;///记得标记回来

        Remain += CurLen;///赋值回来!搜索题代码应当注意的地方!

    }else{
        for(int i=id; i<n; i++){
            if(i>0 && (sticks[i]==sticks[i-1] && !vis[i-1])) continue;///剪枝:排序后,如果有数字不能返回true,说明在此刻选
                                                                      ///择同样的数字也是一样的结果,所以跳过

            if(vis[i] || Lack < sticks[i]) continue;

            Lack -= sticks[i];
            vis[i] = true;

            if( DFS(i, Lack) ) return true;

            Lack += sticks[i];
            vis[i] = false;

            if(sticks[i] == Lack) break;///剪枝:如果当前if成立,说明刚刚的DFS肯定是
                                        ///到达过Lack==0的,既然不返回true,那么说明
                                        ///此方案不行,不必继续往下面搜下去了!
        }
    }
    return false;
}

bool cmp(int fir, int sec){ return fir > sec; }

int main(void)
{
    while(~scanf("%d", &n) && n){
        int tot = 0;

        for(int i=0; i<n; i++){
            scanf("%d", &sticks[i]);
            tot += sticks[i];///累计总和
            vis[i] = false;
        }

        sort(sticks, sticks+n, cmp);///排序方便剪枝

        bool ok = false;
        for(int Len=sticks[0]; Len<=tot/2; Len++){
            if(tot % Len == 0){
                Remain = tot;///将Remain重置,代表当前搜索状态下总长度还剩多少,如果为0说明成功
                CurLen = Len;///全局变量记录当前枚举的是哪个因数,方便深搜操作
                if(DFS(0, Len)){
                    printf("%d
", Len);
                    ok = true;
                    break;
                }
            }
        }

        if(!ok) printf("%d
", tot);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/qwertiLH/p/7955340.html