hdu 1455 Sticks(DFS+剪枝)

本文详细介绍了在解决HDU1455问题时遇到的超时问题,并提供了四个关键剪枝策略来优化DFS算法,包括选择最优组合、优先使用较大元素、确保组成的可行性及答案为sum的约数。通过实施这些策略,从TLE提升至0ms。

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

hdu 1455 : http://acm.hdu.edu.cn/showproblem.php?pid=1455

这道题是大一学习dfs时学习的,但是发现自己现在还是不会写,写着写着超时了。主要是两个剪枝想不到了,代码中给注释了。网上也有好多这道题的做法,我不多说了。

用的是没有返回值的dfs。

剪枝1:答案必须是sum的约数。

剪枝2:从大到小排序减小递归深度。

剪枝3:例如某个组合用到4,原序列中有4也有3,1,那么优先使用4,因为3,1的用处更大,就是代码中的break剪枝。

剪枝4:最重要的剪枝,第一个数一定要能够组成。

#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;

int sticks[65];
bool vis[65];
int n, sum;
bool flag = false;

int cmp(const int a, const int b) {
    return a > b;
}
// 最怕不写dfs参数注释的人了。。。。
// pos寻找可用木棍的开始位置,avg原始木棍的长度,
// cnt表示已经凑得的原木棍数,add正在组合的木棍长度
void dfs(int pos, int avg, int cnt, int add) {
    if(cnt == sum / avg || flag == 1) {
        flag = 1;
        return ;
    }
    for (int i = pos; i < n; i ++) {
        if(!vis[i]) {
            if(add + sticks[i] == avg) {
                vis[i] = 1;
                dfs(0, avg, cnt + 1, 0);
                vis[i] = 0;
                break;  // 如果大的数能够使用,小的数也能使用,优先使用大的数。
            } else if(add + sticks[i] < avg) {
                if(i > 0 && !vis[i-1] && sticks[i] == sticks[i-1]) {
                    continue;
                }
                vis[i] = 1;
                dfs(i + 1, avg, cnt, add + sticks[i]);
                vis[i] = 0;
            }
            // 第一根木棍一定能够组成一组,这个剪枝从TLE到0ms
            if(pos == 0) {
                return ;
            }
        }
    }
}
int main() {
    while (~scanf("%d", &n), n) {
        sum = 0, flag = false;
        for (int i = 0; i < n; i ++) {
            scanf("%d", sticks + i);
            sum += sticks[i];
        }
        sort(sticks, sticks + n, cmp);
        for (int i = sticks[0]; i <= sum / 2; i ++) {
            if(sum % i == 0) {
                memset(vis, 0, sizeof(vis));
                dfs(0, i, 0, 0);
                if(flag == 1) {
                    printf("%d\n", i);
                    break;
                }
            }
        }
        if(flag == 0) {
            printf("%d\n", sum);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值