logo

動的プログラミングまたは DP

動的プログラミング は、複雑な問題をより単純な部分問題に分割することで解決するために、数学とコンピューター サイエンスで使用される方法です。各部分問題を 1 回だけ解決して結果を保存することで、冗長な計算が回避され、幅広い問題に対するより効率的な解決策が得られます。この記事では、例を示しながら動的プログラミングの概念を詳しく説明します。

C++ セット

動的プログラミング

目次



動的プログラミング (DP) とは何ですか?

動的プログラミング (DP) は、複雑な問題をより単純な部分問題に分割することで解決するために、数学とコンピューター サイエンスで使用される方法です。各部分問題を 1 回だけ解決して結果を保存することで、冗長な計算が回避され、幅広い問題に対するより効率的な解決策が得られます。

動的プログラミング (DP) はどのように機能しますか?

  • 副次的な問題を特定します。 主な問題を、より小さな独立したサブ問題に分割します。
  • ストアソリューション: 各部分問題を解決し、その解をテーブルまたは配列に保存します。
  • ソリューションを構築する: 保存されている解決策を使用して、主要な問題の解決策を構築します。
  • 冗長性を避ける: DP は解を保存することで、各部分問題が 1 回だけ解決されるようにし、計算時間を短縮します。

動的プログラミング (DP) の例

例 1: フィボナッチ数列を見つける問題を考えてみましょう。

フィボナッチ数列: 0、1、1、2、3、5、8、13、21、34、…

ブルートフォースアプローチ:

ブルートフォースアプローチを使用して n 番目のフィボナッチ数を見つけるには、単に次の値を追加します。 (n-1) 番目 そして (n-2)番目 フィボナッチ数。これは機能しますが、値が大きい場合は非効率的になります。 n 、以前のすべてのフィボナッチ数を計算する必要があるためです。

動的プログラミングのアプローチ:

動的計画法を使用したフィボナッチ数列

  • 副次的な問題: F(0)、F(1)、F(2)、F(3)、…
  • ストアソリューション: 計算された F(n) の値を保存するテーブルを作成します。
  • ソリューションを構築する: F(n) については、テーブル内の F(n-1) と F(n-2) を検索して加算します。
  • 冗長性を避ける: このテーブルにより、各部分問題 (F(2) など) が 1 回だけ解決されることが保証されます。

DP を使用すると、部分問題を再計算することなく、フィボナッチ数列を効率的に計算できます。

Javaは乱数を生成します

例 2: 最長共通部分列 (2 つの文字列に共通する最長部分列を見つける)

例 3: グラフ内の最短パス (グラフ内の 2 つのノード間の最短パスを見つける)

例 4: ナップザック問題(与えられた容量のナップザックに入れることができるアイテムの最大値を求める)

動的プログラミング (DP) をいつ使用するか?

動的プログラミングは、次の特性からなる問題を解決するときに使用される最適化手法です。

1. 最適な下部構造:

最適な部分構造とは、部分問題の最適な結果を組み合わせて、より大きな問題の最適な結果を達成することを意味します。

Javaでの整数から文字列への変換

例:

を見つける問題を考えてみましょう。 最低コスト からの加重グラフ内のパス ソース ノードから 行き先 ノード。この問題は、次のような小さなサブ問題に分解できます。

  • を見つける 最小 料金 からのパス ソース それぞれへのノード 中級 ノード。
  • を見つける 最小 料金 それぞれからの道のり 中級 ノードへの 行き先 ノード。

より大きな問題の解決策 (ソース ノードから宛先ノードまでの最小コスト パスを見つける) は、これらの小さなサブ問題の解決策から構築できます。

2. 重複する副問題:

同じ部分問題が、問題の異なる部分で繰り返し解決されます。

例:

を計算する問題を考えてみましょう。 フィボナッチ数列 。インデックスでフィボナッチ数を計算するには n 、インデックスのフィボナッチ数を計算する必要があります n-1 そして n-2 。これは、インデックスでのフィボナッチ数を計算する部分問題が次のことを意味します。 n-1 インデックスでのフィボナッチ数を計算するというより大きな問題の解決策で 2 回使用されます。 n

動的プログラミング (DP) のアプローチ

動的プログラミングは、次の 2 つのアプローチを使用して実現できます。

1. トップダウンアプローチ (メモ化):

トップダウンアプローチとも呼ばれます。 メモ化 、最終的な解決策から始めて、それを再帰的に小さなサブ問題に分割します。冗長な計算を避けるために、解決された部分問題の結果をメモ化テーブルに保存します。

トップダウンアプローチを詳しく見てみましょう:

  • 最終的な解決策から始めて、それをより小さなサブ問題に再帰的に分割します。
  • 副問題の解をテーブルに保存して、冗長な計算を回避します。
  • 部分問題の数が多く、その多くが再利用される場合に適しています。

2. ボトムアップアプローチ (集計):

ボトムアップアプローチとも呼ばれます。 集計 、最小のサブ問題から始めて、最終的な解決策まで徐々に構築していきます。冗長な計算を避けるために、解決された部分問題の結果をテーブルに保存します。

ボトムアップアプローチを詳しく見てみましょう:

  • 最小の部分問題から始めて、徐々に最終的な解決策に到達します。
  • ボトムアップ方式でサブ問題の解決策を表に記入します。
  • 部分問題の数が少なく、より小さな部分問題の解から最適解を直接計算できる場合に適しています。

動的プログラミング (DP) アルゴリズム

動的プログラミングは、複雑な問題をより小さな部分問題に分割し、将来の使用に備えてその解決策を保存することで、複雑な問題を解決するアルゴリズム手法です。を含む問題に特に効果的です。 重複する部分問題 そして 最適な下部構造。

動的プログラミングを使用する一般的なアルゴリズム:

  • 最長共通部分列 (LCS): 2 つの文字列間の最長の共通部分シーケンスを検索します。
  • グラフ内の最短パス: グラフ内の 2 つのノード間の最短パスを検索します。
  • ナップザックの問題: 指定された容量のナップザックに入れることができるアイテムの最大値を決定します。
  • 行列チェーン乗算: 行列の乗算の順序を最適化して、演算数を最小限に抑えます。
  • フィボナッチ数列: n番目のフィボナッチ数を計算します。

動的プログラミングの利点 (DP)

動的プログラミングには、次のような幅広い利点があります。

  • 同じ部分問題を複数回再計算する必要がなくなり、大幅な時間の節約につながります。
  • 考えられるすべての組み合わせを考慮して、最適なソリューションが確実に見つかるようにします。
  • 複雑な問題をより小さく、より管理しやすいサブ問題に分割します。

動的計画法の応用 (DP)

動的プログラミングには、次のような幅広い用途があります。

npmクリーンキャッシュ
  • 最適化: ナップザック問題、最短経路問題、最大部分配列問題
  • コンピュータサイエンス: 最長共通部分列、編集距離、文字列マッチング
  • オペレーションズリサーチ: 在庫管理、スケジュール設定、リソース割り当て

それでは、動的プログラミングを習得するための包括的なロードマップを見てみましょう。

動的プログラミング (DP) の基礎を学ぶ

動的プログラミング (DP) の高度な概念

  • ビットマスキングと動的プログラミング |セット1
  • ビットマスキングと動的プログラミング |セット-2 (TSP)
  • 桁DP |導入
  • サブセットの合計 |動的プログラミング

動的プログラミング (DP) 問題点

標準的な動的プログラミング (DP) の問題を、易、中、難の 3 つのカテゴリに分類しました。

1. 動的計画法(DP)の簡単な問題

  • フィボナッチ数
  • n番目のカタルーニャ語番号
  • ベル番号 (セットを分割する方法の数)
  • 二項係数
  • コイン両替問題
  • 部分集合和問題
  • nCr % p を計算する
  • ロッドを切る
  • ペイントフェンスアルゴリズム
  • 最長共通部分列
  • 最長の増加サブシーケンス
  • 隣接するもの間の差が 1 であるような最長のサブシーケンス
  • すべて 1 の最大サイズ正方部分行列
  • 最小コストパス
  • 終了に到達するまでの最小ジャンプ数
  • 最長共通部分文字列 (スペース最適化された DP ソリューション)
  • ステップ 1、2、または 3 を使用して n 番目の階段に到達する方法を数えます
  • mXn 行列の左上から右下までの可能なパスをすべてカウントします。
  • 障害物のあるグリッド内の固有のパス

2. 動的計画法 (DP) の中の問題

  • フロイド・ウォーシャルのアルゴリズム
  • ベルマン・フォードアルゴリズム
  • 0-1 ナップサック問題
  • 0/1 ナップサック内のアイテムを印刷する
  • 無制限のナップザック (アイテムの繰り返しが許可されています)
  • 卵落としパズル
  • 単語区切り問題
  • 頂点カバーの問題
  • タイルのスタッキングの問題
  • 箱の積み重ねの問題
  • パーティションの問題
  • 巡回セールスマン問題 |セット 1 (単純な動的プログラミング)
  • 最長の回文部分列
  • 最長共通増加部分列 (LCS + LIS)
  • 配列のすべての個別のサブセット (またはサブシーケンス) の合計を検索します。
  • 重み付けされたジョブのスケジューリング
  • Count Derangements (要素が元の位置に表示されないような並べ替え)
  • 回文を形成するための最小挿入数
  • ワイルドカード パターン マッチング
  • 隣接するボールが異なるタイプになるようにボールを配置する方法

3. 動的計画法 (DP) に関する難しい問題

  • 回文パーティショニング
  • ワードラップの問題
  • 画家のパーティション問題
  • ブリッジとトーチ問題のプログラム
  • 行列連鎖乗算
  • 行列連鎖乗算問題で括弧を印刷する
  • 2D行列の最大合計長方形
  • 最大 k 回の株の売買で最大の利益を得る
  • さまざまなコストの逆演算を使用して文字列をソートするための最小コスト
  • 配列内の AP (算術級数) サブシーケンスの数
  • ツリー上の動的プログラミングの概要
  • 任意のノードをルートと見なせる場合のツリーの最大高さ
  • 重複しない最長の繰り返し部分文字列

クイックリンク:

  • データ構造とアルゴリズムを学ぶ | DSA チュートリアル
  • 動的プログラミングに関する面接の質問トップ 20
  • 動的計画法の「練習問題」
  • 動的計画法に関する「クイズ」