POJ 1011 (经典搜索)

这道题 是 比较经典的 搜索题。

题意:

给出一堆小木棍的长度,需要把它们拼成几根相同的大棍子,求 这些大棍子的最短长度

分析:这道题主要使用,深度搜索+递归,当然这里用到多次剪枝,这对于减小时间复杂度很有效。

#include
#include
using namespace std;

int stick[64];
int used[64];
int len;
int n;

bool DFS(int i,int l,int s){  //i表示棍子序号,l表示拼成一根棍子还需多长,s表示所有棍子的总长度
    if(l == 0){
        s = s - len;
        if(s == 0)
            return true;
        for(i=0;used[i];i++);    //剪枝,从没有用过的树枝开始
        used[i] = 1;
        if(DFS(i+1,len-stick[i],s))   return true;
        used[i] = 0;
        s = s + len;
    }
    else{
        for(int j=i;j0&&(stick[j]==stick[j-1]&&!used[j-1]))   //剪枝,长度一样的木棍,前面如果没用到,相应的,后面的也是没用的
                continue;
            if(!used[j]&&l>=stick[j]){   //剪枝,需要的长度肯定要大于等于当前的木棍长度
                l = l - stick[j];
                used[j] = 1;
                if(DFS(j,l,s))    return true;
                used[j] = 0;
                l = l + stick[j];
                if(stick[j] == l)   //执行到这步,说明当前的木棍可以,但是后面的搜索失败,所以得退回上一级
                    break;
            }
        }
    }
    return false;
}

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

int main(){
    int i,sum;
    while(cin>>n,n){
        sum = 0;
        for(i=0;i>stick[i];
            sum = sum + stick[i];
            used[i] = 0;
        }
        sort(stick,stick+n,cmp);
        bool flag = false;
        for(len = stick[0];len<=sum/2;len++){ //剪枝,原始长度 肯定大于 剪过之后最长的,小于总和
            if(sum % len == 0){    //剪枝,总和肯定能被 原始长度len整除
                if(DFS(0,len,sum)){
                    flag = true;
                    cout<

至于为什么要将 树枝 从大到小 排列,从一篇 博客里 有写,这样能使 后面的 选择更加灵活些。

关于剪枝,实质上,我觉得就是 除去一些 不需要考虑的无关情况,加快程序的执行。

你可能感兴趣的:(算法设计,C++,搜索)