uva307 dfs

把博客当作一个记录代码的地方吧。这个题想一想还真的挺不错的,能提高对回溯法的理解。题意不难理解,一堆切开的小木棒,然后把这些小木棒合起来,找到这些合起来的小木棒的最小长度,最关键的一点这些小木棒合起来的长度都是一样的。

我开始的思路试枚举多少根小木棒,然后通过总的除以根数就得到了小木棒的长度,然后一一去判断,结果写着写着怎么也不会写了,就从网上借鉴了大神们的代码。思路:直接枚举长度,然后通过递归求根数然后判断相乘之后能否等于总长度即可,这里要注意的就是枚举的长度一定要大于等于木棒的最大长度,小于等于总长度。网上的大神貌似都用到了剪枝,但我觉得剪不剪都一样(可能是自己太弱了,看不出区别)所以就没有用到剪枝。不多说,上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxed=100+10;
int panDuan[maxed],n,muBang[maxed],changDu,zong;
int main()
{
    bool slove(int,int,int);
    bool cmp(int,int);
    while(scanf("%d",&n)!=EOF&&n){
        //memset(panDuan,0,sizeof(panDuan));
        memset(muBang,0,sizeof(muBang));
        int t;
        zong=0;
        for(int i=0;i<n;i++){
            scanf("%d",&t);
            muBang[i]=t;
            zong+=t;
        }
        sort(muBang,muBang+n,cmp);//对木棒长度进行排序,这样每次都从最大的开始找,会节省很多时间。
        for(changDu=muBang[0];changDu<=zong;changDu++)
            if(!(zong%changDu)){
                //cout<<2<<endl;
                memset(panDuan,0,sizeof(panDuan));
                if(slove(0,0,0))
                    break;
            }
        printf("%d\n",changDu);
    }
    return 0;
}
bool cmp(int x,int y)
{
    return x>y;
}
bool slove(int now,int geShu,int cur)//now当前长度,geShu当前的木棒根数,cur当前枚举到的位置(这里一定要写位置,如果每次都从0开始枚举会出现时间溢出)
{
    //cout<<1<<endl;
    if(geShu*changDu==zong)
        return true;
    for(int i=cur;i<n;i++){
        if(panDuan[i])
            continue;
//        if(i&&!panDuan[i-1]&&muBang[i]==muBang[i-1])
//            continue;
        if(now+muBang[i]==changDu){
            panDuan[i]=1;
            if(slove(0,geShu+1,0))
                return true;
            panDuan[i]=0;
            return false;
        }
        else if(now+muBang[i]<changDu){
            panDuan[i]=1;
            if(slove(now+muBang[i],geShu,i+1))
                return true;
            panDuan[i]=0;
            if(now==0)
                return false;
        }
    }
    return false;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值