最优值没有留下回家的路
王城每年举行一次盲人厨师大赛。
厨师们把食材放在一条长桌上。评委允许把桌面切成若干段,每段选一个“代表食材”定价,再把各段得分相乘。
赛后公告只公布最高总分,冠军本人却拿不到自己的菜单。
地图官说:“分数已经在榜上。”
厨师说:“我晚上要按这份菜单回家。”
问题在于,评委每次比较两份菜单,只留下较大的分数。
小的那份连同它的食材、分割点、价格,一起被擦掉。第二轮比较又擦一遍。
王后要求补发一张路线图。厨房里没人知道,最高分那张菜单在两轮擦除里换过几次主人。
简化题面
┌─ [P3592] 洗车店
├─ 平台: 洛谷
├─ 题意: 在区间动态规划中求最优代价,并输出达到最优值的具体方案。
├─ 输入: 一段序列及其代价参数。
├─ 输出: 最优值与每个位置最终所属的方案信息。
├─ 数据范围: 区间长度与值域决定状态数量。
├─ 关键限制: 状态经过多层取最大或最小后,仍需恢复实际决策。
└─ 完整题面: https://www.luogu.com.cn/problem/P3592
数字还在,来路没了
P3592 的计算有两层选择。
固定区间最低价为第 k 档时,dp[l][r][k] 要在许多位置 p 中取最优。随后 best[l][r][k] 又在所有 k' >= k 的状态里取后缀最优。
求值时,一个数字足够。还原时,两轮 max 各自抹掉了一层身份。
ch[l][r][k] best 从哪个实际价格档 kk 来
last[l][r][kk] dp 在该价格档选择哪个位置 p
这两张表对应两次选择。外层先决定价格档,内层再决定分裂位置。
先找价格,再找位置
从 best[1][n][k] 开始还原时,顺序必须和计算依赖相反:
int kk = ch[l][r][k];
int p = last[l][r][kk];
answer[p] = price[kk];
trace(l, p - 1, kk);
trace(p + 1, r, kk);
直接读取 last[l][r][k] 会把外层后缀选择漏掉。last 在实际采用的 kk 状态里才有意义。
价格档确定以后,p 才是当前区间的真实分裂点。先找位置,等于拿另一张菜单上的刀工路线来切案板。
相等也需要证人
还有一个很小的等号:
if (candidate >= dp[state]) {
dp[state] = candidate;
last[state] = p;
}
只写 > 时,最优值仍可能正确。初值和候选同为 0,last 却一直没有合法位置。
也可以使用明确的未初始化哨兵,或在最后重新扫描转移寻找等式成立的决策。方法可以换,证据必须留下。
评委只发分数,厨师要菜单
动态规划若只要求最优值,状态可以把候选压成一个数。题目一旦要求方案、路径、构造或解释,每次压缩都要同时保留“这个数从谁那里来”。
值是结论。ch 和 last 是证书链。
链上任何一环缺席,分数仍能打印,菜单已经回不来了。
王后收到两张纸:一张写最高总分,一张写每次选择的来源。她把第二张交给厨师,第一张留在公告栏。
夜里,厨房的灯灭了。厨师沿着证书链切回家,案板上没有多出一刀。
发布信息草案
- 标题:
最优值没有留下回家的路 - 摘要:多层最优化会逐层抹去决策来源,方案还原必须为每一层保留独立的来源记录。
- 标签:区间 DP、方案还原、决策记录、证书、路径恢复

