15303105423 发表于 2025-6-20 17:03:43

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



https://dajuwangluo.cn/zb_users/upload/2025/05/202505311748682879256516.jpg

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

[*]降序排序加速剪枝
[*]计算长度总和确定搜索范围
[*]核心递归逻辑:bool dfs(int remain, int target, int start) {
    // 终止条件处理
    // 遍历候选木棍
    // 多重剪枝判断
}

[*]五大剪枝策略:

[*]长度单调性剪枝
[*]相同长度跳过
[*]失败长度记忆
[*]首尾失败提前终止
[*]长度下限优化
三、完整C++实现
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;

int sticks, n, sum;
bool used;

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

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

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

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


来源:(CSP-J 2024真题)洛谷P11229小木棍:DFS剪枝优化实战指南 | 附完整注释代码
页: [1]
查看完整版本: (CSP-J 2024真题)洛谷P11229小木棍:DFS剪枝优化实战指南