算法 {记录DP路径}
记录DP路径
定义
假如最终DP答案是DP[x]
, 我们求出来 x
对应的DP路径 (即以x
为终点的 DAG图中的路径);
比如你的答案路径是a->b->c
(这个路径的值等于DP[c]
), 最终你拿着这个DP[c]
的值 想要知道 他的前驱节点是谁, 因此 需要一个DPrec[x]
来表示 谁更新的DP[x]
(也就是以x
为终点的最终路径上 x
的前驱节点是谁), 即DPrec[c]=b, DPrec[b]=a
;
.
参见@LINK: (https://editor.csdn.net/md/?not_checkout=1&articleId=130448844)-(@LOC_2)
;
性质
@DELI;
记录DP路径, 你DP的更新方式 是前驱/后继都可以;
从DAG的角度,DP路径 一定是DPrec[ 终点] = 起点
(比如有条边a->b
则记录DPrec[b] = a
不会反过来); 说白了, DP记录的是: 哪个前驱节点 得到的当前DP;
这与前驱/后继的DP更新方式 是毫无关系的, 对于前驱更新 即DP[cur] <- DP[pre]
记录DPrec[cur] = pre
, 而对于后继更新方式 DP[cur] -> DP[nex]
则记录DPrec[nex] = cur
; 都可以记录DP路径, 而且DPrec
的定义是一致的 即DPrec[x] = 谁更新的DP[x]
;
错误
#错误做法#: 等DP流程处理完后 再倒着(即反向遍历DAG序)再跑一遍 去构造DPrec[]
, 而且这也不一定可行 因为对于后继更新方式 你倒着来 也无法获得其前驱节点呀… 而且即使是前驱方式 你倒着遍历DAG序 也非常麻烦;
其实不管是前驱/后继更新方式, 你都可以让 DP过程 和 DPrec
记录路径 两个步骤 同时进行, 就在原先DP的基础上 再加一行代码即可: 当DP转移时 即DP[a] 更新了 DP[b]
那就记录一个DPrec[b] = a
;
算法
后继更新方式
就在原先DP代码的基础上, 直接嵌入这个代码即可;
curDP = DP[cur];
if( curDP 可以更新 DP[nex]){
更新DP[nex];
DPrec[ nex] = cur;
}
前驱更新方式
就在原先DP代码的基础上, 直接嵌入这个代码即可;
curDP = DP[cur];
if( DP[pre] 可以更新 curDP){
更新DP[cur];
DPrec[ cur] = pre;
}
应用
@LINK: https://editor.csdn.net/md/?articleId=138968666
;
反向DP + 最小字典序;