当前位置:首页 > 比赛题解 > (CSP-J 2024真题)洛谷P11229小木棍:DFS剪枝优化实战指南 | 附完整注释代码

(CSP-J 2024真题)洛谷P11229小木棍:DFS剪枝优化实战指南 | 附完整注释代码

1天前比赛题解35

   截图未命名.jpg (CSP-J 2024真题)洛谷P11229小木棍:DFS剪枝优化实战指南 | 附完整注释代码 DFS剪枝优化 木棍拼接算法 CSP-J真题解析 深度优先搜索技巧 竞赛编程实战 第1张

一、题目深度解读

这是一个典型的组合优化问题:

  • 问题核心:给定若干小木棍,拼接成若干根长度相同的大木棍

  • 输入要求:n根小木棍的长度(n≤65)

  • 输出目标:求可能的最短大木棍长度

  • 算法挑战:需要高效处理指数级搜索空间

二、DFS+剪枝算法框架

  1. 预处理阶段

    • 降序排序加速剪枝

    • 计算长度总和确定搜索范围

  2. 核心递归逻辑

    bool dfs(int remain, int target, int start) {
        // 终止条件处理
        // 遍历候选木棍
        // 多重剪枝判断
    }
  3. 五大剪枝策略

    • 长度单调性剪枝

    • 相同长度跳过

    • 失败长度记忆

    • 首尾失败提前终止

    • 长度下限优化

三、完整C++实现

#include <algorithm>
#include <iostream>
#include <cstring>
using namespACe std;

int sticks[70], n, sum;
bool used[70];

bool dfs(int remain, int target, int start) {
    if (remain == 0) return true;
    for (int i = start; i < n; i++) {
        if (used[i] || sticks[i] > target) continue;
        used[i] = true;
        if (sticks[i] == target) {
            if (dfs(remain-1, sum/(remain-1), 0)) 
                return true;
        } else if (dfs(remain, target-sticks[i], i+1)) 
            return true;
        used[i] = false;
        // 剪枝优化点
        if (target == sum/remain) break;
        while (i+1 <n && sticks[i+1]==sticks[i]) i++;
    }
    return false;
}

int main() {
    while (cin >> n && n) {
        sum = 0;
        for (int i = 0; i < n; i++) {
            cin >> sticks[i];
            sum += sticks[i];
        }
        sort(sticks, sticks+n, greater<int>());
        for (int len = sticks[0]; len <= sum; len++) {
            if (sum % len) continue;
            memset(used, 0, sizeof used);
            if (dfs(sum/len, len, 0)) {
                cout << len << endl;
                break;
            }
        }
    }
    return 0;
}

四、性能优化分析

  1. 时间复杂度:最坏O(n!) → 剪枝后实际运行效率显著提升

  2. 空间复杂度:O(n) 主要消耗在排序和状态记录

  3. 竞赛技巧

    • 降序排序优先尝试大木棍

    • 使用全局变量减少参数传递

    • 位运算优化状态记录


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。