(CSP-J 2024真题)洛谷P11229小木棍:DFS剪枝优化实战指南 | 附完整注释代码
一、题目深度解读
这是一个典型的组合优化问题:
问题核心:给定若干小木棍,拼接成若干根长度相同的大木棍
输入要求:n根小木棍的长度(n≤65)
输出目标:求可能的最短大木棍长度
算法挑战:需要高效处理指数级搜索空间
二、DFS+剪枝算法框架
预处理阶段:
降序排序加速剪枝
计算长度总和确定搜索范围
核心递归逻辑:
bool dfs(int remain, int target, int start) { // 终止条件处理 // 遍历候选木棍 // 多重剪枝判断 }
五大剪枝策略:
长度单调性剪枝
相同长度跳过
失败长度记忆
首尾失败提前终止
长度下限优化
三、完整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; }
四、性能优化分析
原创内容 转载请注明出处