查看: 37|回复: 0

(CSP-J 2024真题)洛谷P11229小木棍:DFS剪枝优化实战指南

[复制链接]
  • TA的每日心情
    无聊
    昨天 10:41
  • 签到天数: 12 天

    [LV.3]偶尔看看II

    10

    主题

    0

    回帖

    37

    积分

    新手上路

    Rank: 1

    积分
    37
    发表于 2025-6-20 17:03:43 | 显示全部楼层 |阅读模式




    一、题目深度解读
    这是一个典型的组合优化问题:
    • 问题核心:给定若干小木棍,拼接成若干根长度相同的大木棍
    • 输入要求:n根小木棍的长度(n≤65)
    • 输出目标:求可能的最短大木棍长度
    • 算法挑战:需要高效处理指数级搜索空间

    二、DFS+剪枝算法框架
    • 预处理阶段

      • 降序排序加速剪枝
      • 计算长度总和确定搜索范围

    • 核心递归逻辑
      bool dfs(int remain, int target, int start) {
          // 终止条件处理
          // 遍历候选木棍
          // 多重剪枝判断
      }
    • 五大剪枝策略

      • 长度单调性剪枝
      • 相同长度跳过
      • 失败长度记忆
      • 首尾失败提前终止
      • 长度下限优化

    三、完整C++实现
    1. #include <algorithm>
    2. #include <iostream>
    3. #include <cstring>
    4. using namespace std;

    5. int sticks[70], n, sum;
    6. bool used[70];

    7. bool dfs(int remain, int target, int start) {
    8.     if (remain == 0) return true;
    9.     for (int i = start; i < n; i++) {
    10.         if (used[i] || sticks[i] > target) continue;
    11.         used[i] = true;
    12.         if (sticks[i] == target) {
    13.             if (dfs(remain-1, sum/(remain-1), 0))
    14.                 return true;
    15.         } else if (dfs(remain, target-sticks[i], i+1))
    16.             return true;
    17.         used[i] = false;
    18.         // 剪枝优化点
    19.         if (target == sum/remain) break;
    20.         while (i+1 <n && sticks[i+1]==sticks[i]) i++;
    21.     }
    22.     return false;
    23. }

    24. int main() {
    25.     while (cin >> n && n) {
    26.         sum = 0;
    27.         for (int i = 0; i < n; i++) {
    28.             cin >> sticks[i];
    29.             sum += sticks[i];
    30.         }
    31.         sort(sticks, sticks+n, greater<int>());
    32.         for (int len = sticks[0]; len <= sum; len++) {
    33.             if (sum % len) continue;
    34.             memset(used, 0, sizeof used);
    35.             if (dfs(sum/len, len, 0)) {
    36.                 cout << len << endl;
    37.                 break;
    38.             }
    39.         }
    40.     }
    41.     return 0;
    42. }
    复制代码


    四、性能优化分析
    • 时间复杂度:最坏O(n!) → 剪枝后实际运行效率显著提升
    • 空间复杂度:O(n) 主要消耗在排序和状态记录
    • 竞赛技巧

      • 降序排序优先尝试大木棍
      • 使用全局变量减少参数传递
      • 位运算优化状态记录



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

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表