POJ 1011 (经典搜索)

本文介绍了一道经典搜索题目,通过深度优先搜索与递归的方法,结合巧妙的剪枝技巧,解决将多根小木棍拼接成等长的大木棍问题,并详细分析了算法思路与实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题意:

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

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

#include<iostream>
#include<algorithm>
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;j<n;j++){
            if(j>0&&(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<n;i++){
            cin>>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<<len<<endl;
                    break;
                }
            }
        }
        if(!flag)
            cout<<sum<<endl;
    }
    return 0;
}

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值