题目背景
在华为 OD 机试中,"伐木工"是一道经典的动态规划与贪心结合的题目。核心需求是将一根长度为 X 的树木切割成若干正整数长度的段,使得这些段长度的乘积最大。允许不切割(即整根交易),但通常切割能获得更高收益。
问题分析
这道题本质上等价于 LeetCode 上的 "Integer Break"(整数拆分)问题。数学上有一个有趣的结论:当长度大于 4 时,尽可能多地切出长度为 3 的段收益最高;如果剩余长度为 1,则将一个 3 和 1 合并为两个 2。
不过,考虑到面试场景下可能需要输出具体的切割方案(各段长度),而不仅仅是最大乘积值,使用动态规划(DP)更为稳妥。DP 不仅能算出最大值,还能通过回溯记录路径,还原出具体的切割组合。
解题思路
我们定义 dp[i] 表示长度为 i 的木材能得到的最大乘积。对于每个长度 i,我们可以尝试切成 j 和 i-j 两部分。这里要注意,i-j 部分既可以不再切分,也可以继续切分得到更优解,所以状态转移方程是:
dp[i] = max(dp[i], j * (i - j), j * dp[i - j])
同时,我们需要一个辅助数组 path[i] 来记录为了达到 dp[i] 最优解时,最后一段切下来的长度是多少。这样在计算完所有长度后,从 X 开始不断回溯 path,就能得到所有的切割段。
代码实现
下面是完整的 JavaScript 解决方案,适配 OD 机试的输入输出格式。
function solve() {
// 模拟标准输入读取,实际环境中根据平台调整
const input = require('fs').readFileSync(0, 'utf-8').trim();
if (!input) return;
const n = parseInt(input);
if (n <= 1) {
console.log(n); // 特殊情况处理
return;
}
// dp[i] 存储长度为 i 时的最大乘积
const dp = new Array(n + 1).fill();
path = (n + ).();
dp[] = ;
path[] = ;
( i = ; i <= n; i++) {
maxVal = ;
bestCut = ;
( j = ; j < i; j++) {
val = .(j * (i - j), j * dp[i - j]);
(val > maxVal) {
maxVal = val;
bestCut = j;
}
}
dp[i] = maxVal;
path[i] = bestCut;
}
result = [];
curr = n;
(curr > ) {
cut = path[curr];
result.(cut);
curr -= cut;
}
result.( a - b);
.(result.());
}
();

