14.7 まとめ¶
- 動的プログラミングは問題を分解し、部分問題の解を保存することで冗長な計算を避け、計算効率を向上させます。
- 時間を考慮しなければ、すべての動的プログラミング問題はバックトラッキング(力任せ探索)を使用して解決できますが、再帰木には多くの重複する部分問題があり、効率が非常に低くなります。記憶化リストを導入することで、計算されたすべての部分問題の解を保存し、重複する部分問題が一度だけ計算されることを保証できます。
- 記憶化探索はトップダウンの再帰解法であり、動的プログラミングはボトムアップの反復アプローチに対応し、「表を埋める」ことに似ています。現在の状態は特定の局所状態のみに依存するため、dpテーブルの1次元を削除して空間計算量を削減できます。
- 部分問題の分解は汎用的なアルゴリズムアプローチであり、分割統治法、動的プログラミング、バックトラッキングで特徴が異なります。
- 動的プログラミング問題には3つの主要な特徴があります:重複する部分問題、最適部分構造、無記憶性。
- 元の問題の最適解がその部分問題の最適解から構築できる場合、最適部分構造を持ちます。
- 無記憶性とは、状態の将来の発展が現在の状態のみに依存し、過去に経験したすべての状態に依存しないことを意味します。多くの組み合わせ最適化問題にはこの特性がなく、動的プログラミングを使用して迅速に解決することはできません。
ナップサック問題
- ナップサック問題は最も典型的な動的プログラミング問題の1つで、0-1ナップサック、無制限ナップサック、複数ナップサックなどの変種があります。
- 0-1ナップサックの状態定義は、最初の \(i\) 個のアイテムを含む容量 \(c\) のナップサックでの最大値です。アイテムをナップサックに入れないまたは入れるという決定に基づいて、最適部分構造を特定し、状態遷移方程式を構築できます。空間最適化では、各状態が直接上と左上の状態に依存するため、左上の状態の上書きを避けるためにリストを逆順で走査する必要があります。
- 無制限ナップサック問題では、各種類のアイテムを選択できる数に制限がないため、アイテムを含める状態遷移は0-1ナップサックと異なります。状態が直接上と左の状態に依存するため、空間最適化では前方走査を含める必要があります。
- コイン交換問題は無制限ナップサック問題の変種で、「最大」値を求めることから「最小」コイン数を求めることに変わり、状態遷移方程式は \(\max()\) を \(\min()\) に変更する必要があります。ナップサックの容量を「超えない」ことを追求することから、正確に目標金額を求めることに変わり、「目標金額を構成できない」無効解を表すために \(amt + 1\) を使用します。
- コイン交換問題IIは「最小コイン数」を求めることから「コインの組み合わせ数」を求めることに変わり、状態遷移方程式を \(\min()\) から和算演算子に変更します。
編集距離問題
- 編集距離(レーベンシュタイン距離)は2つの文字列間の類似度を測定し、一つの文字列を別の文字列に変更するために必要な最小編集ステップ数として定義され、編集操作には追加、削除、置換が含まれます。
- 編集距離問題の状態定義は、\(s\) の最初の \(i\) 文字を \(t\) の最初の \(j\) 文字に変更するために必要な最小編集ステップ数です。\(s[i] \ne t[j]\) の場合、追加、削除、置換の3つの決定があり、それぞれに対応する残余部分問題があります。これから最適部分構造を特定し、状態遷移方程式を構築できます。\(s[i] = t[j]\) の場合、現在の文字の編集は必要ありません。
- 編集距離では、状態が直接上、左、左上の状態に依存します。したがって、空間最適化後、前方走査も逆走査も正しく状態遷移を実行できません。これに対処するため、変数を使用して左上の状態を一時的に保存し、無制限ナップサック問題の状況と同等にし、空間最適化後に前方走査を可能にします。