Skip to content

動的計画法の最適解復元

概要

動的計画法(DP)では最適値(例: 最短手数・最大価値)を求めるだけでなく、最適解そのもの(例: 具体的な経路・選んだ品物)を復元することができる。

最適値を求める解説は多いが、最適解を復元する方法はあまり詳しく解説されていない。

最適解を復元する 2 つの方法

方法 1: 素朴なやり方

ゴールから逆順に「1 つ前の状態になりうるもの」を探索して辿る方法。

例: 迷路の最短路で手数 16 のゴールから「15 → 14 → … → 0 」と逆に辿る。

欠点: 各ノードの近傍の探索範囲が広い場合に時間がかかる。最悪オーダーレベルで計算量が悪化することもある。

方法 2: 汎用的な方法(推奨)

DP テーブルの更新時に、どのノードから伝播して来たかを同時にメモしておく方法。

prev[next] = current  // どこから伝播してきたかを記録

テーブル更新時に処理を 1 行追加するだけで実現できる。 ゴールから prev 配列を辿ることで最適解を復元できる。

利点: 近傍探索が不要なため、方法 1 の欠点を解消できる。

方法の使い分け

状況 推奨方法
近傍探索が軽い場合 どちらでも可(方法 1 は実装が楽)
近傍探索コストが高い場合 方法 2

具体例

また、最長増加部分列(LIS)の長さの求め方 は「長さのみ」を求めるアルゴリズムだが、この方法を応用することで具体的な LIS も復元できる。

応用: 辞書順最小な解の復元

一般に最適解は複数存在することが多い。そのうち辞書順最小のものを求めたい場合、ゴール側からスタートに向けて DP の更新を行うことで実現できる。

  • 通常: スタート → ゴール方向に DP を計算 → ゴールから prev を逆辿り
  • 辞書順最小: ゴール → スタート方向に DP を計算 → スタートから順に辿る

スタートからゴール方向へ辿ることで、辞書順が最小となる経路を自然に選べる。

応用: 最適解の数え上げ

DP の更新部分をほんの少し修正することで、最適解の 個数 も同時に数え上げることができる。 詳細は「最短経路の個数も一緒に数え上げる最短経路アルゴリズム」などを参照。

引用元: 意外と解説がない!動的計画法で得た最適解を「復元」する一般的な方法