ダイナミックプログラミングは - ナップザック問題をはじめ

ダイナミックプログラミングは - ナップザック問題をはじめ


1.01バックパック


アウトライン

N個のアイテム、特定のボリュームと値を有する各オブジェクトを与え、それぞれが1つのオブジェクトのみを有しています。バックパックはパッケージがバックパックで最大のオブジェクトの合計値を作成するためにインストールする必要があるか尋ね、体積Vを持っていますか?

問題解決のためのアイデア

ナップザック問題は、典型的な動的プログラミングクラスのタイトルで、そしてダイナミックな計画が正のソリューションを識別するために、法律によって方法の典型的なものです。だから、鍵が異なるデータ間の関係(状態遷移)を見つけるためにどのように問題解決のアイデアです。

直接の説明は一例として、私たちの例を説明するために便利ではありません。

(注:01ナップザック問題は、問題の形状や大きさの物体を伴い、どのようにバックパックを入れていない、単にボリュームと各オブジェクトが液体であり、これは当然の大きなバックパックタンク(あるとして、我々は理解することができる値を考慮してください。各液体は、すべてのいずれかの中に注ぎ入れ、またはそれが低下しない、一部をダウンできません。)


例:HDU2602 ボーン・コレクター

問題

何年も前に、テディの故郷で「ボーン・コレクター」と呼ばれた男がありました。この男は、このような犬の、牛のように、骨の異なる集めるのが好き、また、彼は墓に行ってきました...
、明らかに、骨のコレクタはVのボリュームと大きな袋を持っていて、収集の彼の旅に沿って骨がたくさんあります別の骨は、現在、彼の旅に沿って各ボーンの値を指定した別の値と異なるボリュームを持っていますが、骨のコレクターが得ることができる合計値の最大値を計算することができますか?

単純な定義

昔、テディの家にそれは人々の「骨コレクター」と呼ばれてきました。人々は、骨のすべての種類を収集したい-犬、牛、もちろん、彼は多くの場合、周りの墓地に行くだろう......(狼オフ)の
人はバックパックのVの総容量を有し、彼の旅行で彼は、骨の多くを収集する必要があります。そして明らかに、異なる骨が異なるサイズと異なる値を持ちます。今、彼が何であるかを見つけ、すべての骨を与え、骨の最大値がどのくらいある収集するために、1袋に入れることができた計算?

入力

最初の行は整数T、ケースの数を含みます。
Tケース続いて、それぞれの場合三行、最初の行は、骨の数と彼の袋の容積を表す2つの整数N、V、(N <= 1000、V <= 1000)を含みます。そして、2行目は、各骨の値を表すN個の整数が含まれています。第三のラインは、各骨の体積を表すN個の整数を含みます。

入力形式

最初の行の入力が異なる場合(データセット)の数の整数T、代表を含んでいます。
Tは三行は、最初の行は、2つの整数N、V含有する場合、続いて(Nを<= 1000 、V <= 1000) 番号及び骨容量バックパックの代表。2行目は、Nが各骨の整数値を表す含ま。第三のラインは、各骨の体積のNの整数を表すが含ま。

出力

合計値の最大値を表す1行に1つの整数(この数はより少なくなる\ \(2 ^ {31}) )。

出力フォーマット

各最大値の合計値を表す整数を回線(この数は以下である\(2 ^ {31} \) )。

サンプル入力

1
5 10
1 2 3 4 5
5 4 3 2 1

サンプル出力

14

トピック分析

達成するために可能な地元のさまざまなソリューションを必要とし、動的プログラミング、可能な限り最高のソリューションを実現するために、最適な解決策を見つけると、他のソリューションを放棄するために、それらの局所解を見つけ、「マイナーなものに大きな問題を。」 。
この質問に、このオオカミパックは、さまざまな方法の数千人を破壊した、そこに局所解の数千人がありますが、私たちが見つける必要があると、その種の最大値であるが、これは何千ものです局所用溶液であり、これは最適解である方法のいずれかの種類、。

私たちは、データのセットを与えます:

1
3 5
5 12 20
1 2 4

まず、データを保存することができます:

各骨に番号をコンパイルし、各骨の音量オフ狼V [B]、値は[B] wのですが、Bである、我々はすでに良い宣言しています:

    int T;
    scanf("%d",&T);
    for(int c=1;c<=T;c++)
    {
        int N,V;
        scanf("%d%d",&N,&V);
        for(int b=1;b<=N;b++)
            scanf("%d",&w[b]);
        for(int b=1;b<=N;b++)
            scanf("%d",&v[b]);
        }

パッケージをインストールする方法についての彼の選択プロセスは、彼のある意思決定のプロセス。

彼は最初の骨を取る見てまず:
骨5の部分の値を、ボリュームは1です。
私たちは、これだけの骨、我々は唯一の骨の部分にそれを置くことができますどのくらい私たちのバックパック、そしてどんなにを持っています。そして、そのような関係があります:

の合計値 1 2 3 4 5 6 7 ...... バックパックのボリューム
1 5 5 5 5 5 5 5 ......
いいえ骨ません

今オオカミがオフと彼の第2の骨拾っ:ボリュームが3以上であるならば、彼のバックパックを、その後、彼は2つの骨の中に入れることができます。

-
彼のバックパックのボリューム1は、彼が唯一の骨1の部分を置くことができ、値が最大値である5であり、
彼のバックパックのボリューム2が、彼は骨2の部分を置くことができ、値は12で、最大値であり、
彼のバックパックのボリュームは、彼は値が17である、骨2のピースと骨1を置くことができ、3だった最大値であり、
彼のバックパックの容量は4だった、彼はまだだけ骨2のピースと骨1を置くことができ、値は17で、最大の値;
その後、彼のバックパックの容量がどんなに大きな、彼は唯一の骨1及び2に骨を置くことはできませんので、今後の値は17です。

の合計値 1 2 3 4 5 6 7 ...... バックパックのボリューム
1 5 5 5 5 5 5 5 ......
2 5 12 17 17 17 17 17 ......
いいえ骨ません

4巻、20の値:それから彼は彼の第三の骨から出てきました。

-
彼のバックパックのボリューム1は、彼が唯一の骨1の部分を置くことができ、値が最大値である5であり、
彼のバックパックのボリューム2が、彼は骨2の部分を置くことができ、値は12で、最大値であり、
彼のバックパックのボリュームは、彼は値が17で、骨と骨2 1の一部を置くことができ、3だったこれに最大の価値は以前と同じであるです。
彼のバックパックの容量は4だった、彼は骨3を置くことができ、その値は、最大の20であり、
彼のバックパックの容量は5だった、彼は骨3の一枚プラス25である骨1を置くことができ、
彼のバックパックのボリューム6、彼は32であり、骨2に加え、骨3を置くことができ、
彼のバックパックボリューム7を、彼は骨3の片、骨2、骨1を置くことができ、それは37であり、
それ以降、彼それはどのような場合には3つだけの骨、37が戻っていることを意味します。

の合計値 1 2 3 4 5 6 7 ...... バックパックのボリューム
1 5 5 5 5 5 5 5 ......
2 5 12 17 17 17 17 17 ......
3 5 12 17 20 25 32 37 ......
いいえ骨ません

......

そのようなテーブルがあるので、私たちはテーブルを置くことができます。配列をしてみましょう:

int dp[i][j];//在这里,表示考虑到前i块骨头,背包体积为j,可以获得的最大价值。那么dp[i][j]就是这种情况下的最大价值。

この配列は次のようになります。

DP [I] [J] 1 2 3 4 5 6 7 ...... J
1 5 5 5 5 5 5 5 ......
2 5 12 17 17 17 17 17 ......
3 5 12 17 20 25 32 37 ......

一見法律もないようだ、と次のキーである-動的計画の本質である、このデータテーブルに法律を見つける:状態遷移方程式の導出を - 、オフ狼である意思決定プロセス。

しかし、このオオカミはオフに私は、彼は私がパッケージに入れたいと思う問題の骨の唯一の彼の作品を検討する必要があるの骨の一部を取得します。
彼は彼の決定にそれを開催することを決定した場合には、次のとおりです。DP [I] [J]はDP [I-1] [j]を=;
-バッグ事は変わっていない、と[I-1] [j]のときのパッケージそれは同じです。

彼は置くことを決めた場合は、その後、彼が終了する決定:DP [I] [J]はDPを= [I-1] [JV [i]は] + [I]ワット;
-彼は、番号iの骨の中にバッグを置きますそのボリュームはまた、[I] [i]はVを取り上げますが、ワットの価値以上してきたが、袋は、骨番号iの部分を持っています。この時間-ラウンド後、他の方法は、彼がdpの後に入った[I] [j]は----「彼は私を入れていないということです、JVボリュームは、その状態で、[I] iのプラス時間値」 - !

(シンプルなものは...少しは脳の手紙を燃え尽きQAQを得ます)

彼は開催することを決定したのであれば、その状態[i]の[j]をあそこに[I-1]〜[J]から転送され、
彼はその後、状態を置くことを決めた場合は[i] [j]は[I-1]であります[JVは、[I]]そこから転送され、
彼はすべての権利ホールドを入れて、私たちは、最大値を探しているので、この時間は状態があります-

dp[i][j]=max(dp[i-1][j-v[i]]+w[i],dp[i-1][j]);//Note:j>=v[i];

そして、これは私たちがいる限りOKがあるように、プログラムにそれを配置する必要があり、問題を解決するための状態遷移方程式であります:

#include<cstdio>
#include<algorithm> //max()的头
using namespace std;
int dp[1080][1080];
int w[1080],v[1080];
int main()
{
    int T;
    scanf("%d",&T);
    for(int c=1;c<=T;c++)
    {
        int N,V;
        scanf("%d%d",&N,&V);
        for(int b=1;b<=N;b++)
            scanf("%d",&w[b]);
        for(int b=1;b<=N;b++)
            scanf("%d",&v[b]);
        for(int i=1;i<=N;i++)//i个物品
            for(int j=0;j<=V;j++)//背包体积为j——转两个循环列举各个情况的状态,并用不同的状态进行转移:
            {
                if(j>=v[i])//使用状态转移方程
                    dp[i][j]=max(dp[i-1][j-v[i]]+w[i],dp[i-1][j]);
                if(j<v[i])//如果此时背包的体积比这个物体的体积小,那无论如何也放不进去,所以走“不放”的状态转移
                    dp[i][j]=dp[i-1][j];
            }
        printf("%d\n",dp[N][V]);
    }
    return 0;
}

......


彼は置く方法を決定しなければならないので、彼は万人の意思決定、この状態では確かに最適な疲れS.を見つける複数の様々な、持っている:あなたが外を見ることができます
そして、我々は彼と一緒に一つだけの骨を開始し、2つの骨を推定、3つの骨......それらに連絡して、あなたはどのように転送プロセスを継続するために、我々は非常に簡単になります必要がありますNの骨を置くために彼を見つけることができます見つけます動的計画で最適解、見つけるの「マイナーなものまで大きな問題うち、」思考の本質を。


おすすめ

転載: www.cnblogs.com/izwb003/p/dynamic-programming_knapsack-problem.html