web-dev-qa-db-ja.com

動的プログラミングを理解するための良い例、記事、本

動的プログラミングの原理を理解することはできませんし、本当に欲しいのです。 DPは非常に強力で、次のような問題を解決できます。

数値の差から可能な限り低い合計を取得する

だから、ダイナミックプログラミングとは何かを説明する私の良い本や記事(できれば実際のコードの例を使用)を提案できますか?まず最初に単純な例が本当に欲しいので、次に進みます。

41
good_evening

ダイナミックプログラミング は、ハードな問題をより小さなサブ問題に分割することにより、ハードな問題を最適化するために使用できる便利なタイプのアルゴリズムです。部分的なソリューションを保存して再利用することで、貪欲なアルゴリズムを使用することの落とし穴を回避できます。ダイナミックプログラミングには、ボトムアップとトップダウンの2種類があります。

動的計画法を使用して問題を解決できるようにするには、問題が 最適な部分構造 と呼ばれるもののプロパティを持っている必要があります。つまり、問題が一連のサブ問題に分割され、各サブ問題の最適なソリューションが見つかった場合、結果のソリューションはこれらのサブ問題のソリューションによって実現されます。この構造を持たない問題は、動的プログラミングでは解決できません。

トップダウン

トップダウンは memoization として知られています。毎回再計算を避けるために、過去の計算を保存するという考え方です。

再帰関数が与えられた場合、次のように言います:

fib(n) = 0 if n = 0
         1 if n = 1
         fib(n - 1) + fib(n - 2) if n >= 2

これを数学的な形から次のように簡単に再帰的に書くことができます。

function fib(n)
  if(n == 0 || n == 1)
    n
  else
    fib(n-1) + fib(n-2)

さて、しばらくプログラミングをしていたり​​、アルゴリズムの効率性について知っている人なら誰でも、これはひどい考えだと言うでしょう。その理由は、各ステップで、fib(i)の値を再計算する必要があるためです。ここで、iは2..n-2です。

これのより効率的な例は、これらの値を保存し、トップダウンの動的プログラミングアルゴリズムを作成することです。

m = map(int, int)
m[0] = 0
m[1] = 1
function fib(n)
  if(m[n] does not exist)
    m[n] = fib(n-1) + fib(n-2)

これを行うことにより、fib(i)を最大で1回計算します。


一気飲み

ボトムアップでは、トップダウンで使用されるのと同じメモ化手法が使用されます。ただし、ボトムアップでは、最終結果を最適化するために、再発と呼ばれる比較副問題が使用されるという違いがあります。

ほとんどのボトムアップの動的プログラミングの問題では、多くの場合、決定を最小化または最大化しようとしています。任意の時点で2つ(またはそれ以上)のオプションが与えられ、解決しようとしている問題に対してどちらがより最適であるかを決定する必要があります。ただし、これらの決定は、以前に行った選択に基づいています。

各ポイント(各サブ問題)で最適な判断を下すことにより、全体的な結果が最適になるようにします。

これらの問題の最も難しい部分は、問題を解決するための再発関係を見つけることです。

大量のアルゴリズムの教科書を購入するために、nアイテムのあるストアを奪うことを計画しています。問題は、 tiny knapsack は最大[〜#〜] w [〜#〜]kgしか保持できないことです。各アイテムの重量(w [i])と値(v [i])がわかっているので、盗難品の価値を最大化するには、すべてを合わせて最大Wにします。各アイテムについて、バイナリ選択を行う必要があります-それを取るか、それを残す。

次に、サブ問題が何であるかを見つける必要があります。非常に明るい泥棒であるため、最大重量wを持つ特定のアイテムiの最大値をm [i、w]で表すことができることに気付きます。さらに、m [0、w](最大重量wの0アイテム)およびm [i、0](最大重量0のiアイテム)は常に0値に等しくなります。

そう、

m[i, w] = 0 if i = 0 or w = 0

フルフェイスマスクをオンにすると、バッグにできるだけ多くの重量を入れた場合、その重量が最大重量とバッグの現在の重量。アイテムを検討するもう1つのケースは、バッグ内のアイテムの重量が重量以下であるが価値がある場合です。

 m[i, w] = 0 if i = 0 or w = 0
           m[i - 1, w] if w[i] > w
           max(m[i - 1, w], m[i - 1, w - w[i]] + v[i]) if w[i] <= w

これらは上記の繰り返し関係です。これらの関係ができたら、アルゴリズムを書くのは非常に簡単です(そして短い!)。

v = values from item1..itemn
w = weights from item1..itemn
n = number of items
W = maximum weight of knapsack

m[n, n] = array(int, int)
function knapsack
  for w=0..W
    m[0, w] = 0
  for i=1 to n
    m[i, 0] = 0
    for w=1..W
      if w[i] <= w
        if v[i] + m[i-1, w - w[i]] > m[i-1, w]
           m[i, w] = v[i] + m[i-1, w - w[i]]
        else
           m[i, w] = m[i-1, w]
      else
        m[i, w] = c[i-1, w]

  return m[n, n]

追加のリソース

  1. アルゴリズムの紹介
  2. プログラミングの課題
  3. アルゴリズム設計マニュアル

問題の例

幸いなことに、競争力のあるプログラミングに関しては、動的プログラミングは本当にinになりました。 VAJudgeでのダイナミックプログラミング をチェックして、ダイナミックプログラミングの問題を繰り返し実行する能力をテストする練習問題を確認してください。

34
Ian Bishop

要するに、ダイナミックプログラミングは、複雑な問題をより簡単なステップに分解することによって、つまり、問題を段階的に解決することによって解決する方法です。

  1. 動的プログラミング ;
  2. ダイナミックプログラミングの概要 ;
  3. MITのアルゴリズム入門、講義15:動的計画法 ;
  4. アルゴリズム設計 (本)。

このリンクが少なくとも少し役立つことを願っています。

10

皮切りに

あなた自身をテストしたい場合、オンライン裁判官についての私の選択は

そしてもちろん

良い大学のアルゴリズムコースもチェックできます。

結局、問題を解決できない場合は、SOここに多くのアルゴリズム依存者が存在することを尋ねてください

6
user467871

下記参照

上記の記事で参照しているサンプルや記事が多すぎます。

ダイナミックプログラミングを学んだ後、[〜#〜] uva [〜#〜]問題、UVAのdiscussion boardにUVA動的プログラミングの問題のリストがあります

また、Wikiには簡単なサンプルがあります。

編集:本アルゴリズムについては、以下を使用できます:

また、動的プログラミングのMemoizationを見てください。

5
Saeed Amiri

代数動的プログラミング 言及する価値があると思います。 DPテクニックの非常に刺激的なプレゼンテーションであり、バイオインフォマティクスコミュニティで広く使用されています。また、最適性のベルマンの原則は非常にわかりやすい方法で述べられています。

従来、DPは例によって教えられています。アルゴリズムは、中間の問題に対する解決策を格納するテーブルエントリ間の再帰の観点からキャストされ、このテーブルから全体的な解決策はいくつかのケース分析によって構築されます。

ADPは、問題をサブ問題に分解し、ケース分析を意図した最適化の目的から完全に分離するように、DPアルゴリズムを編成します。これにより、DPアルゴリズムのさまざまな部分を再利用し、同様の問題に組み合わせることができます。

ADPアルゴリズムには、3つの疎結合部分があります。

  • 探索空間の構築(ツリー文法の観点から述べられています);
  • サーチスペースの各要素のスコアリング。
  • 興味のある探索空間の要素を選択する目的関数。

このすべての部分が自動的に融合され、効果的なアルゴリズムが生成されます。

4
max taldykin

このUSACOの記事 は、DPの基本と、それが途方もないスピードアップをもたらす方法を理解するための良い出発点です。次に、 このTopCoderの記事 をご覧ください。これも基本をカバーしていますが、あまりよく書かれていません。 CMUのこのチュートリアルも非常に優れています。それを理解したら、参照する問題を解決するために2D DPに飛躍する必要があります。 このTopcoderの記事 リンゴの質問(ラベルの付いた中間)まで読んでください。

また、ビデオから物を拾う度合いに応じて、 this MITビデオ講義 を見るのも便利です。

また、DPを正常に取得するには、再帰をしっかりと把握する必要があることに注意してください。 DPはhard!しかし、本当に難しいのは解決策を見ることです。 DPの概念(上記を参照してください)を理解し、ソリューションのスケッチ(たとえば、 質問に対する私の答え を適用すると、実際に適用するのはそれほど難しくありません)なぜなら、DPソリューションは通常非常に簡潔で、理解しやすい再帰的ソリューションの反復バージョンからそれほど遠くないからです。

memoization もご覧ください。これは理解しやすい人もいますが、多くの場合、DPと同じくらい効率的です。簡単に説明すると、メモ化は再帰関数を使用して結果をキャッシュし、将来同じ引数の結果を再計算することを節約します。

3
marcog

動的プログラミングで解決できるのはいくつかの問題のみです

誰もまだ言及していないため、動的プログラミングソリューションを適用するために必要なプロパティは次のとおりです。

  • 重複するサブ問題いくつかのサブ問題が複数回発生するように、元の問題をサブ問題に分割することが可能でなければなりません。単純な再帰に対するDPの利点は、これらの副問題のそれぞれがonceのみ解決され、必要に応じて結果が保存され、再利用されることです。つまり、DPアルゴリズムは時間とメモリを交換します。
  • 最適な部分構造副問題に対するoptimal解のみを使用して、副問題に対する最適解を計算できる必要があります。このプロパティが保持されていることを確認するには、慎重に考える必要があります。

例:すべてのペアの最短パス

DPアルゴリズムの典型的な例として、 Floyd-Warshallアルゴリズム を使用して、グラフ内のすべての頂点のペア間の最短パスの長さを見つける問題を考えます。

1からnまでの番号が付けられたn頂点があるとします。頂点ab間の最短経路の長さである関数d(a, b)の計算に興味がありますが、他から効率的に計算する方法を見つけることは困難です関数d()の値。

3番目のパラメータcを導入し、abの間の範囲内の頂点のみを訪れる最短パスの長さになるようにd(a, b, c)を定義しましょう1からcまで。 (これらの頂点すべてにアクセスする必要はありません。)これは追加する意味のない制約のように見えますが、次の関係があることに注意してください。

d(a, b, c) = min(d(a, b, c-1), d(a, c, c-1) + d(c, b, c-1))

上記のmin()の2つの引数は、2つの可能なケースを示しています。頂点1からaのみを使用してbからcに到達する最短の方法:

  1. c(この場合、最初の_c-1_頂点のみを使用した最短パスと同じ)を回避します。または
  2. cを経由します。この場合、このパスはaからcへの最短パスに続いてcからbへの最短パスでなければならず、両方のパスは間にある1から_c-1_の範囲の頂点のみを訪問します。この場合(cを経由する)が短い場合、これらの2つのパスは同じ頂点のいずれにもアクセスできません。なぜなら、それらの場合はすべての頂点(c)それらの間で、ケース1が代わりに選択されます。

この定式化は最適な部分構造特性を満たします-より大きな問題に対する最適な解決策を見つけるために、サブ問題に対するoptimal解決策を知ることだけが必要です。 (すべての問題ではないこの重要な特性がある-たとえば、頂点のすべてのペア間のlongestパスを見つけたい場合、このアプローチは失敗するaからcへの最長パスは、cからbへの最長パスによっても訪問される頂点を訪問できます。)

上記の機能的関係、およびd(a, b, 0)abの間のEdgeの長さに等しい境界条件(またはそのようなEdgeが存在しない場合は無限大)を知っている、 _c=1_から始めて_c=n_までのd(a, b, c)のすべての値を計算することができます。 d(a, b, n)は、abの間の最短距離であり、その間の任意の頂点を訪れることができます-探している答えです。

2
j_random_hacker

アルゴリズムの入門書のほぼすべてに、動的プログラミングの章があります。私はお勧めします:

1
kunigami

アルゴリズムについて学びたい場合は、MIT講義の非常に優れたビデオが利用可能であることがわかりました。

たとえば、 6.046J/18.410Jアルゴリズムの概要(SMA 5503) は非常に良い方法です。

このコースでは、他の多くの有用なアルゴリズム手法の中でも、動的プログラミングを扱います。私の個人的な意見では、使用された本は非常に優れており、アルゴリズムについて学ぶことに真剣な人にとっては非常に価値のあるものです。

さらに、コースには課題のリストなどが付属しているため、実際に理論を実践することもできます。

関連する質問:

1
bcosca

問題を解決するために動的プログラミングを試してみると、その背後にある概念を理解するようになると思います。 Google codejamでは、参加者に「 CodeJamへようこそ 」というプログラムが提供されると、動的プログラミングの優れた使用方法が明らかになりました。

0
Senthil Kumaran

MIT Opencourseware 6.00コンピュータサイエンスとプログラミング入門

0
romeroqj

通信数学の修士課程の一環として、私は本に基づいてコースを行いました http://www.Amazon.co.uk/Introduction-Programming-International-mathematics-computer/dp/0080250645/ref=sr_1_4?ie = UTF8&qid = 1290713580&sr = 8-4 これは実際にはプログラミングの角度というより数学的な角度ですが、時間と労力を割くことができるなら、それは非常に徹底的な入門書であり、私にとってはコースとしてはうまくいったようです本のほとんどが実行されました。

また、Sedgewickの本「Algorithms」の初期バージョンもあります。そこには、動的プログラミングに関する非常に読みやすい短い章があります。彼は今、戸惑うほど高価な本を販売しているようです。アマゾンで見ると、同じ名前の章があるようです http://www.Amazon.co.uk/gp/product/toc/0201361205/ref=dp_toc?ie=UTF8&n=266239 =

0
mcdowella

Steven LaValleによるPlanning Algorithmsには、動的プログラミングに関するセクションがあります。

http://planning.cs.uiuc.edu/

インスタンスのセクション2.3.1を参照してください。

0
Alejandro