DPの接触を学習するために、ほとんどの初心者は、多くの場合、DPのナップザック問題がたくさんある場合は、我々はいくつかのバックパックDP一般的な問題を議論したいためにここにいます。
ナップザック問題、0-1ナップザック問題
//オプションのi番目の項目が選択されていないか、または; - 実現は、MAX(コスト[I])+値[I] REC(I + 1、J)、REC(I + 1、j)を返します
このメモリ起因実現DPアレイ生成することである:DP [I] [J]:まず、iはi番目の項目を示していることに注意し、jが残りの値を示し、その後、全体DP表現はIであります最後の項目に項目N - 1、彼の最大値を生成することができます。
同様に、我々は再帰的な関係を使用して、我々は知ることができます
DP [I] [J] = MAX(DP [I + 1] [j]は、DP [I + 1] [j - W [I] +値[I])。
書式#include <iostreamの> の#include <cstdioを> する#include <cstdlib> 書式#include <CStringの> の#include <cmath> の#include <CCTYPE> 書式#include <アルゴリズム> 書式#include <ベクトル> の#include <キュー> の#include <リスト> 書式#include <マップ> 書式#include <スタック> の#include < 設定 > 書式#include < 文字列 > 使用して名前空間はstdを、 const int型 MAX_N = 1010 ; 1010 ; int型DP [MAX_N] [MAX_W]。 int型N、W; INT [MAX_N]、値[MAX_N] W。 INT メイン() { CIN >> N >> W。 用(int型 i = 0 ; iがNを<; I ++)は、CIN >> W [i]は>> 値[I]。 DP [N] [ 0 ] = 0 。 フィル(DP [N]、DP [N] + W、0 ); 以下のために(int型 I = N - 1 ; I> = 0 ; i-- ){ ため(INT J = 0 ; J <= W; J ++){ 場合(j < W [i])と DP [I] [J] = DP [I + 1 ] [J]。 他 DP [I] [J] = MAX(DP [I + 1 ] [j]は、DP [I + 1 ] [JW [I]] + 値[I])。 } } 戻り 0 。 }
あなたは少し不快に感じる場合は言葉の導出に対するので、我々は単に変更のDPの配列定義のために、我々は最後まで私のオリジナルDP [I] [J]から使用することができ、同様に、DP [私は+ 1] [J ]私たちは、私は、Geは、この記事1 + 0からIに設定することができますが、注意を払う必要があります。
書式#include <iostreamの> の#include <cstdioを> する#include <cstdlib> 書式#include <CStringの> の#include <cmath> の#include <CCTYPE> 書式#include <アルゴリズム> 書式#include <ベクトル> の#include <キュー> の#include <リスト> 書式#include <マップ> 書式#include <スタック> の#include < 設定 > 書式#include < 文字列 > 使用して名前空間はstdを、 const int型 MAX_N = 1010 ; 1010 ; int型DP [MAX_N] [MAX_W]。 int型N、W; INT [MAX_N]、値[MAX_N] W。 INT メイン() { CIN >> N >> W。 用(int型 i = 0 ; iがNを<; I ++)は、CIN >> W [i]は>> 値[I]。 フィル(DP [ 0 ]、DP [ 0 ] + W、0 ); 用(int型 I = 0 ; iがNを<I ++は{) のために(INT J = 0 ; J <= W; J ++ ){ もし J(< W [i])と DP [I + 1 ] [j]は= DP [I] [j]を。 他 DP [I + 1 ] [J] = MAX(DP [I]、[J]、DP [I] [JW [I]] + 値[I])。 } }
のprintf( "RESULT:%Dを\ n"、DP [N] [W])。 リターン 0 ; }
最長共通部分列問題:
だから我々はすべて見ることができ、問題に追いつくために、そして私が代わりに次の配列の範囲の主題を防ぐため、巧妙な1を設定するのではI + 1を+レノボDPのナップザック問題!
DP [I + 1] [J + 1]:これは、S0 [i]が質問S0 [j]のときに、2つの文字列、彼の現在の最長共通部分列の長さの2つの要素を指し
その後、我々は、上下のレベルの関係を見つけるために、問題をキャッチするためのメソッドを使用します。
もしこれがS0である場合にのみ、[I] = S1 [J]、DP [I + 1] [j + 1] DP [I] [J] + = 1。
時間は、この式を満たさない場合
DP [I + 1] [J + 1] = MAX(DP [I + 1] [j]は、DP [I]、[J +1])//最後の二つが等しくないので、これは、同時に使用することはできません私たちはあなたにも問題を軽減することができ、スケールを削除する必要があります!
#include <iostreamの> する#include <CStringの> する#include <ビット/ STDC ++。H> の#include <アルゴリズム> の#include <cstdioを> する#include <cstdlib> の#include < ストリング > の#include <CCTYPE> の#include <cmath> 使用 名前空間はstd; const int型 MAX_S = 1010 ; チャーS0 [MAX_S]、S1 [MAX_S]。 int型LEN1、LEN0。 int型DP [MAX_S] [MAX_S]。 INT メイン() { CIN >> S0 >> S1。STRLEN(S0)。 LEN1 = STRLEN(S1)。 フィル(DP [ 0 ]、DP [ 0 ] + MAX_S、0 ); 用(int型 iは= 0 ; iがLEN0を<I ++は{) のために(INT J = 0 ; J <LEN1; J ++ ){ 場合(S0 [I] == S1 [J]){ DP [I + 1 ] [j + 1 ] = DP [I] [J] + 1 。 } 他{ DP [I + 1 ] [j + 1= MAX(DP [I + 1 ] [j]は、DP [I]、[J + 1 ])。 } } } のprintf(" 答えは即ち:%Dを\ n " 、DP [LEN0] [LEN1])。 リターン 0 ; } / * ABCD becd * /
そして最後に兄弟のお気に入りにフルナップザック問題:
0 1と同様に、このバックパックのためので、私たちはそれを再帰どのような状況、無限の数の中に?
最も簡単なのは、私たちの01リュックサックをモデルにしていると考えることが最も簡単には解決され、
私合理的な選択後の商品の最大値の種類 - 前方方向を維持するために、私たちのDP [I + 1] [j]は、プロセスにおける最初のi製品を表し、結果は0です!
したがって、我々はDPを有する[I + 1]〜[J] = MAX(DP [I] - + K *値は、[I] [J [i]はWのk *])、これは添字インデックスがゼロより大きいことを保証することであることに注意してください、そして私たちのkは自然数です。
しかし、その後どのように我々はさらに簡略化するか、このアルゴリズムの複雑さが高すぎることを言っていますか??
DP [I + 1]〜[J] = MAX(DP [I]、[J]、DP [I + 1] [j - W [I] +値[I])。
呼び出しは、この式我々がしなければならないことに注意するときがあります添字インデックスがゼロより大きく、初期化
DP [I + 1]〜[J] = MAX(DP [I] - + K *値[I] [J [i]はWのk *])は、k> = 0。
= MAX(DP [I]、[J]、DP [1] - [I] + K *値[J [i]はワット* K])K> = 1。
= MAX(DP [I]、[J]、DP [I] + K *値[I] +値[I] [J - - W [i]は[I] Wのk *])は、k> = 0。
= MAX(DP [I]、[J]、DP [I + 1] [j - W [I] +値[I])。
そして、これはそれの良い証拠です。