HDU-1455-木棒

这题的话,我们,定义一个结构体,然后把木棒从大到小排序。
这些木棒如果是由多根等长木棒组成的,那目标长度一定大于等于其中最长的木棒长度,所这就是我们搜索的下限。
上限就是所有的木棒组成了一根木棒,就是所有木棒长度的总和,确定了搜索范围之后,我们再来确定搜索的边界。
其实搜索的边界很明显,就是当拼接而成的木棒根数跟我们期望的目标根数相同的时候,这时候,说明我们的假设就是正确的。
至于其它的,就在代码中注释了。

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

struct Stick {
    int len, mark;
    bool operator < (const Stick &s)const {
        return len > s.len;
    }
}stick[100];

int total, l;
int n, sum;
//s已经组成的木棒根数,len正在拼接中的木棒长度,pos位置
int DFS(int s,int len,int pos)
{
    if (s==total)
        return 1;
    for (int i = pos + 1; i < n;i++) {
        if (stick[i].mark)
            continue;
        if (stick[i].len+len==l) {
            stick[i].mark = 1;
            if (DFS(s+1,0,-1))
                return 1;
            stick[i].mark = 0;
            return 0;//如果其中一根无法和其它的任一根拼接,我们就放弃这个长度
        }
        else if (stick[i].len+len<l) {
            stick[i].mark = 1;
            if (DFS(s,len+stick[i].len,i))//我们找的是按序排列的木棍中的下一根进行尝试
                return 1;
            stick[i].mark = 0;//对于main函数中的for循环起效,因为还要搜索其它的长度
            if (len==0)
                return 0;//如果第一层中的第一根无法和其它任一根拼接,我们也放弃这个长度
            while (stick[i].len==stick[i+1].len)
                i++;//对于要进行深搜之前,我们不在搜索相同的长度,此为剪枝
        }
    }
    return 0;
}

int main()
{
    while (scanf("%d",&n)&&n) {
        sum = 0;
        for (int i = 0; i < n;i++) {
            scanf("%d", &stick[i].len);
            sum += stick[i].len;
            stick[i].mark = 0;
        }
        sort(stick, stick + n);
        for (l = stick[0].len; l <= sum ;l++) {
            if (sum%l!=0)
                continue;
            total = sum / l;
            if (DFS(0,0,-1)) {//取长度最长的木棒作为深搜的开始
            //搜的时候,已经组成的木棒为0,已经组成的长度为0,下标保证从0开始
                printf("%d\n", l);
                break;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值