分割統治と同様に、動的プログラミングアルゴリズムは、基本的な考え方は、いくつかのサブの質問、最初のサブ問題解決、元の問題への解決策を提供するために組み合わせるこれらのサブ問題の解決に全体的な問題を打破することです。分割統治法が異なると、分解して動的プログラミング問題を解くサブ問題は、多くの場合、互いに独立していません。
基本的な考え方:
複数のサブ質問に、全体的な問題が発生した後のサブ問題を保持しているテーブルは、テーブルから一般的な質問への答え、完全なオペレーター発行背中を解決されていると、サブ問題を計算する(サブの質問にも、私は打破できなくなるまで、打破し続ける場合があります)答えを探して、別のテーブルに全体の問題で特定の変更で、要件に応じて、最適なソリューションの選択を得られています
手順を設計します。
最適解の性質を検索1.、前記構造を特徴づけるために
分解問題の特性に応じて、問題の解決策は、子供の問題への答えを見つけることができ、特定の問題に応じて構造の特徴をご覧ください
2.再帰的に最適値を定義します
再帰式、最適解=(サブ質問1、2サブ問題、サブ問題...... 3)特定の変更の一般的な質問の条件を満たさなければならない最も適切な解決策の問題に、すなわちサブ答えを書きます+
3.ボトムアップファッション計算し最適な値
右および下添字に上部左からテーブルメモリサブアレイは、典型的には二次元のDPである溶液(0,0)応答サブ問題、特定のサブの計算で問題に格納されている(M、N)に(R、C)は、溶液は、先行答えに、例えばDP [L] [R] = MAX(DP [R-1] [C]、DP [R] [C-1])に応じて+ 1計算されます。溶液問題(R、C)が(R-1 C)および(R、C-1)サブ問題の解であることに基づいて
最適な情報の計算で得られた値は、最適解を構築します
[n]は[M] DP直接一般的に、特定の問題が解決される参照
例
そして、最大のサブセグメント
nは整数(おそらく負の整数)Aの配列から成る所与。1、A 2 ... A Nは、セグメントのサブシーケンスとの最大値(A見つけるL + A L +を1 + A L + 2 + ...... A + R&LT 1- + A R&LT)、0はサブセグメントとして定義される0以上です。
問題の分析、あなたは機能を得ることができます。
1サブセグメントは連続しています
2.ときに負の整数と正の整数の和で全てのサブセグメントの結果は以下0に設定され、サブセグメント、サブセグメントよりも、それが0以上であります
3.最大サブセグメントとサブセグメントは、要素Aになり、私は終了します
(Aで言及I-。1、 A Iは、サブセグメントと二つのサブサブセグメントのセグメントAの最大の終わりである。I- 1とサブセグメントA I)
1と3の関係得るために組み合わせることができる:サブセグメントA iは要素A含める必要がありますIを(それが終了しているために)、サブセグメントA I特定の要素にはAであり、I(なぜなら連続サブセグメントの)、または空(すなわち、唯一の全体副段落I)、その後にIサブセグメントとサブセグメントの端の最大値である:MAX(中I. 1-最大フィールドは、サブセグメントの端部であり、+ I、0)
すなわち、再帰式:DP [I] = MAX( DP [I-1] + [I]、0)( ここで、DP [i]を用いサブセグメントA Iのサブセグメントと、[i]はAを参照I)
(実際には、配列、配列DPの十分な必要はありません)
書式#include <iostreamの> 使用して 名前空間はstdを、 int型のmain() { INTの DP [ 100000 ]、M、N、I。 一方、(CIN >> N) { 以下のための(iは= 0、I <N; I ++ ) CIN >> DP [i]は、 M = DP [ 0 ] = MAX(DP [ 0 ]、0 ); 以下のための(iは= 1 ; I <N; I ++ ) { DP [I] = MAX(DP [I- 1 ] + DP [I]、0 ); M = MAX(M、DP [I])。 } COUT << M << ' \ n ' 。 } リターン 0 ; }
最長共通部分列
所定のシーケンス{X 1 = X、X2 ...のx M }と{Y = Y 1、Y 2、... Y N- }、xおよびyは最長共通サブシーケンスZを見つけます。
既知の小から大良いの大きさ、要素のシーケンスにおけるzサブシーケンスは、必ずしも連続していないのY xは、それが配列xにある必要があり、Yの添字
DP設け[I] [j]は、最初の要素からのx、yの開始のために、それぞれのサブセグメントiは、jを、次にX [i]は、Y [J]のための最長の共通部分列の長さの長さ関係:
iは0又はJJ = = 0の場合、xは、yの一つまたは長さ0の両方が、次いで、さらに0の共通部分列の長さです。
DP [I] [J] = 0
場合X [I] = Y [J]、X [i]は、最長共通部分列の最長共通サブシーケンスの現在時刻におけるY [j]が直接計算される要素の共通のサブシーケンス(DP [I -1]時間[J-1])プラスX [i]は、Y [J]、すなわち:
DP [I] [J] = DP [I-1] [J-1] +1
X [i]は!= Y [J] X [i]は、Y [j]は、直接要素に共通のサブシーケンスとしてカウントすることはできないが、X [i]は、Y [i]は前の要素に起因し得る場合、等しいと共通のサブシーケンスを追加(X [I]!= Y [j]が、しかし同様にX [I] = Y [J-1]、Y [J]であってもよい)、電流が最長共通サブシーケンスX除去する[I ]または両方の場合における最長共通部分列Y [J]の除去シーケンスの大きい方。
DP [I] [J] = MAX(DP [I-1] [j]は、DP [I]、[J-1])
出力サイズDPに応じて最長共通サブ[I] [J]とDP [I-1] [j]は、DP [I]、[J-1]、DP [I-1] [J-1]でありますDPとの関係[I] [J]からの決定(原因ここではwhile文でI、Jは、順番に次の文は、jの不要な変更を、私を確保するためにインクリメントされている場合は、減少しています)
書式#include <iostreamの> 使用して 名前空間はstdを、 INTの DP [ 1001 ] [ 1001 ] = { 0 }、X [ 1001 ]、Y [ 1001 ]、Z [ 1001 ]。 int型のmain() { int型M、N、I、J、K。 一方、(CIN >> M >> N) { 以下のための式(I = 1 ; I <= M; I ++ ) CIN >> X [i]は、 以下のための(iは= 1 ; I <= N; I ++ ) CIN >> Y [i]は、 以下のための(iは= 1、I ++; I <= M ) のための(J = 1 ; J <= N; J ++ ) 場合(!X [I] = Y [J])DP [I] [J] = MAX(DP [I- 1 ] [j]は、DP [I]、[J- 1 ])。 他 DP [I] [J] = DP [I- 1 ] [J- 1 ] + 1 。 K = 0 。 一方、([ - I] [ - DP J]) であれば(DP [I] [J] == DP [I- 1 ] [J])J ++ 。 それ以外の 場合(DP [I] [J] == DP [I] [J- 1 ++ i]は); そう であれば(DP [I] [J]> DP [I- 1 ] [J- 1 ])Z [++ K] = X [i]は、 COUT << DP [M] [N] << ' \ n ' 。 一方、(K)COUT << Z [K - ] << ' ' 。 coutの << ' \ n個' ; } リターン 0 ; }
0-1バックパック
nは、商品の種類やバックパックを考えます。iは、アイテムの重量W I、Vの値iが、ナップサック容量がCであり、物品は繰り返し私を充電することができない、私はアイテムの一部で充電することができません。どのようにバックパック、最大の項目の合計値にバックパックにアイテムを選択するには?
DP設け[I]、[J](1 <= I <=はN、1 <= jが<= C)、iは任意記事1,2 ...... i、jは現在のDPのために、バックパックの電流容量を表したことを示し[I] [J]:
私は初期化時に0またはJ = 0 =時:
DP [I] [J] = 0
場合J <[i]が物品Wが1,2-から選択することができるため、物品は、以前の結果を取って、直接廃棄アイテムiを適合しない...... I-1、jは場合バックパックの容量と同じです。
DP [I] [J] = DP [I-1]〜[J]
この中に置かれたとき、J> = W [i]は、最後の結果では、記事を入れしようとすると、その結果、いずれか大きい方:
DP [I] [J] = MAX(DP [I-1] [j]は、DP [I-1] + V [i]は[I] [JW])
ここで、DP [I-1] [JW [I] + V [I]でいます。
1. [I-1]物品は私は記事記事1,2に配置することができる他の項目の範囲に、私を置くことができるので、...... I-1
2. [JW [I]アイテムバックパック域1,2における少なくともW [i]はI物品が置かれたとき、空間の残りの記憶容量がJWに相当する[I]で脇空間セットを指す......私収納ケース-1
書式#include <iostreamの> 使用して 名前空間はstdを、 INTの DP [ 1001 ] [ 1001 ] = { 0 }、[W 1001 ]、V [ 1001 ]。 int型のmain() { int型N、C、I、J。 一方、(CIN >> N >> C) { 以下のための(iは= 1 ; I <= N; I ++ ) CIN >> [I] >>ワットV [i]は、 ための式(I = 1 ; iが<= N; iが++ ) のために(J = 1 ; J <= C; J ++ ) 場合(J <W [i])とDP [I] [J] = DP [I- 1 ] [ J]; 他 DP [I] [J] = MAX(DP [I- 1 ] [j]は、DP [I- 1 ] [JW [I] + V [I])。 COUT << DP [n]は[C] << ' \ n ' 。 } リターン 0 ; }
編集距離
文字列は、3つの動作モードがあります。
また1:別の文字の文字に任意の文字列
2. [削除]:任意の文字列を削除します。
3.挿入:任意の位置に文字列を追加します
二つの文字列、Bが与えられると、二つの文字列の操作の最小数を求めること(すなわち、編集距離)が等しいです
提供DP [i] [j]は編集距離の[1〜i]は、B [1〜j]をサブストリングB、文字列aを表し、
私は0またはJ = = 0のとき、それは明らかに、少なくとも、空の文字列を表します。
DP [I] [J] = MAX(i、j)は
[I] = B [j]とするとき、[I]、B [j]は、直接[1〜I]、B [1〜j]が編集距離に対応し、負と見なされていない場合:
DP [I] [J] = DP [I-1] [J-1]
!場合は、様々な状況がある[I] = B [J]:
ときに交換作業、[I]またはb [j]が等しくなるように、プラス編集距離の[1〜I-1]、B [1〜J-1]と結合編集距離を変えますすなわち:DP [I] [J] = DP [I-1] [J-1] +1
削除操作は、[I]またはb [j]を削除する場合は、編集距離を加えた[1〜I-1]、B [1〜J](または[1〜i]は、B [1に1を加算〜J-1])すなわち、編集距離:DP [I] [J] = DP [I-1]〜[J] +1(またはDP [I] [J] = DP [I]、[J-1] + 1)
挿入、インサート[I + 1]のように[I + 1] = B [J](B [J + 1]も同様)、プラス1つのプラス編集距離A [1〜I]、B [1〜 J-1](または[1〜I]、B [1〜J-1])すなわち、編集距離:DP [I] [J] = DP [I-1]〜[J] +1(またはDP [ I] [J] = DP [I]、[J-1] +1)
欠失、および挿入は、同じ式を見ることができます
異なる添え字が始まっbのDP [I] [J]と文字列Aので、そうif文I-1、J-1があります
書式#include <iostreamの> 使用して 名前空間はstdを、 int型 DP [ 2001 ] [ 2001 ]; int型のmain() { 整数N、M、I、J。 文字列A、B; しばらく(CIN >> B) { N = a.length()。 M = てb.length()。 以下のための(iは= 0 ; I <= N; I ++ ) DP [I] [ 0 ] = I。 用(J = 0 ; J <= Mであり、j ++ ) DP [ 0 ] [J] = J。 以下のための(iは= 1 ++ I; <I = N ) のための(J = 1、J ++; J <= M ) であれば([I- 1 ] == B [J- 1 ])DP [I] [J] = DP [I- 1 ] [J- 1 ]。 他 DP [I] [J] =分(分(DP [I- 1 ] [j]は、DP [I]、[J- 1 ])、DP [I- 1 ] [J- 1 ])+ 1 。 COUT << DP [n]は[M] << ' \ n ' 。 } リターン 0 ; }