--01可動型破りベースナップザック問題(ナップザック問題Ⅱ)

トピック出典:襟バックル| LintCode

I-及び商品jのバックパックの総容量体重所与のアレイは、各項目の重みを表し、配列値が最大値を見つけ、各項目の値です。(項目を分割することができません)

ナップザック問題II

この質問は、すなわち、再帰的及び再帰(反復)は、前者が後者より良くより理解されている二つの方法で実現動的プログラミング(DP)の基本的な質問のアルゴリズムです。

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

まず、被験者は、私たちは、どのように彼の店、それの最大値を作ることにしたいので、最大値を見つけるために必要ですか?記事では、量を有し、バックパックの容量が限られているので、我々は常に最大の項目の値を置くことができないので、例えば、バックパック10の容量を想定し、重み値と次の表の間の関係対応する3つの項目がある
項目は|品質|値
10 8
B 6 5
C 5 4
明らかに、我々はその後、誰かが点滅することがあります、BとCを選択する必要があり、それはすべてのコスト効果の高い選択肢(値/品質)が行(貪欲アルゴリズム)上で最大のではなく、話題があります私たちが実際に貪欲なアルゴリズムを使用することはできませんので、必要条件「の項目は、分割することはできません」。
私たちは思考の最も一般的な方法から再帰式をプログラミング、動的に取得することができます。我々は、i番目の直線オブジェクトをトラバースように、我々は、通常の人間の考え方によると、口座に事態の重さを取って、i番目のアイテムを持っているが、ライン上の最大のいずれかを選択し、これらの組み合わせの値を比較することで、その後のさまざまな組み合わせを、見つけることであるとき、彼2つのオプションがして、「しない」、「すべきである」、があり
、各項目は、これら2つのオプションを経験している最終的にすべての組み合わせを生成することになります。場合物品のi番目のターン、私たちの最大値は、式である:MAXVALUE = MAX(値[I ]、値[I-1])( それぞれの選択バックパックがあることをふりをすることができ考えます)商品のi番目の値に意味はなく、この式は、項目の完全なバックパックに渡されていたであろうような状況のi番目の記事では、我々はときに私-1の最大値を知る必要があり、裁判官の私の項目以来最大でしたかあなたはこの再帰的プロセスを解決するために期待することはできませんので、すべての上を確認します。

再帰的アルゴリズム

我々は] [重量] [値、それぞれ二つの配列(構造体の配列を使用することもできる)、各項目に対応する情報を格納する必要があり、各番組項目の情報を知る必要があります。再帰的な手順は、パラメータの変化を必要とし、アイテムの重量は、バックパック及び物品の残容量が、(ナップザックjのi番目の項目の前に、残存容量を機能バッグを記述することが可能であることが明らかになるであろうときに値が変化しません);

  1. 見出さ再帰出口は
    、上記残りの空き領域またはバックパック考え完成品、すなわち、(j == 0 || I == 0述べた )、 それは0を返すべき点で最大値を、
  2. 再帰関係
    この関係は、2つの、比較的容易に考えられるMAXVALUE =最大有する(バッグ(I- 1、j)は、バッグ(I-1、J-重量[I])+値[I])を「前であります「べき「後者は、」しないでください。
    また、より多くのスペースの残りの部分よりも、J = 0が、アイテムの重量は、現在選択されている重量[i]のjを、我々はこの記事で、すなわち強制選択をスキップするというケースを! 「ありません」。
    私たちは、それを得るためにこれら二つの予備的な再帰的アルゴリズムを完了することができるようになります!
int bag(int i, int j)  //递归实现
{
    if (i == 0 || j == 0)
        return 0;
    if (weight[i] > j)
        return bag(i-1,j);
    else {
        int res = max(bag(i - 1, j), bag(i - 1, j - weight[i]) + value[i]);
        return res;
    }
        //max函数可以自己判断每一种情况下的最大价值(TIPS:对于递归程序不能刻意去思考它的过程,主要理解它的方向)
}

しかし、効率が非常に悪いため、これは、DPと呼ばれることができない、我々はそれが例数百人を計算見つけ、そこには必然的に繰り返される、項目の繰り返しがノードI、Jの重量であってもよいし、のレコードを作成するために使用することができますその効率を大幅に向上させることができるので、二次元アレイのMAXDATA [i] [j]は、各iについて、jは、場合、このような場合に格納されている最大値であります

int bag(int i, int j)  //递归实现
{
    if (maxdata[i][j] != EOF)   //一开始让每个点都等于EOF(-1),如果不是-1证明这个情况已经算过了,可以直接return
        return maxdata[i][j];
    if (i == 0 || j == 0)
        return 0;
    if (weight[i] > j)
        return bag(i-1,j);
    else {
        int res = max(bag(i - 1, j), bag(i - 1, j - weight[i]) + value[i]);
        maxdata[i][j] = res;     //没算过就存一下
        return res;
    }
}

反復アルゴリズム

反復アルゴリズムは、対照的に、最初から最大値を見つけ、そして徐々にi番目の記事を取得するために立ち上がっながら反復アルゴリズムと再帰の再帰アルゴリズム区別性質上、我々は、i番目の残りの1つのアイテムを発見しました最大値、および私たちは体重の様々な商品のI種類の前に最大の価値ということを記録しなければなりません。(どちらがポイントを理解することはより困難である)
が、具体的な判定方法はまだ「はず」と「ない」の問題です。それは最初からあるので、我々はラウンドキーポイントがある再帰その重量、またはその再帰的な最大値(MAXDATA [j]は、最大のような [J-重量[I]] +値[I]); しかし、私たちこれは、前のラウンドに格納された配列データに基づいて決定されます。
我々は、i番目の記事では、最大値またはi「のない操作を行う」場合それでは、私が商品の種類を計算する場合は、この再帰は、今、MAXDATA [j]は、商品の種類の重量に対応するI-1、jの最大値が何であるかを分析してみましょう-1私たちが「したい」場合は、記事に対応する最大値、i番目の記事では、[i]は、容量の重量を控除1時間項目の前にI-1の最大値に対応し、[i]の値を追加します。このいずれかの最大値としての大きなを選択するこれらの2つの値、新データの無駄がないよう決意に対応するデータが終了しているので= [I]即ちMAXDATA、対応する位置に重ねてもよいですMAX(MAXDATA [J]、最大 [J-重量[I] +値[i])と、
コアコードオファー

    //递推(迭代) 滚动数组
    int f[100] = { 0 };    //f[j]储存前一轮各个重量下最大价值
    for (int i = 1; i <= n; i++) {       //枚举种类
        for (int  j = totalweight; j >= 0; j--){   //算前n种的各个重量下最大价值
            int next_w = j - weight[i];      //“要”这个物品的情况下对应的下标
            if (next_w < 0) next_w = 0;   //防止下标越界
            if (weight[i] > j)
                f[j] = f[j];    //超重则最大价值等于前一轮对应容量下的最大价值,直接“不要”
            else 
                f[j] = max(f[j], f[next_w] + value[i]);
                        if(i==n) break;      //最后一个物品只需要算一个totalweight的就够了
        }
    }//最终得到的f[totalweight]就是n个物品用整个背包去装能得到的最大价值。

私は2は、すべての理解を処理することができるようになります=にこのプロセスを理解する限り、彼らが得るように私は1を=。ランダムな例であることができる:12のバックパックと仮定容量
|記事|品質|数値
。1. 8 A 10
2 B. 6 5
3 4 5 C

  • 容量が少なく8は、データF、他方は0であり、10以下である場合、我々は最大値を見つける最初のものから始まり、[]内のすべてゼロであるが、その後、10以上の後に式F [あろうJ] = MAX(0,0 + 8 )、 新しいF []を得ることができる;
    Fは[] = {0 0 0 0 0 0 0 0 0 0} 8. 8. 8 ......。
  • 第2の項目Bを見て、
    総容量は12であり、F [12] = MAX(Fあり [12]、F [12-6] +5)F [12] フロント星は8に等しいが、 F [6] = 0、この能力の範囲内で、我々が選択することは明らかである「ドはありません。」
    そしてように、まで我々は、{0 0 0 [Fで得] =ことができる、我々は、 "へ"を選択します5 <J <10、見つけることができる ...... 6 6 6 6 8 8 8 0 0 0}
  • それは理解されていない場合、物品は、第三のCを見て継続
    J = 12、F [12] = MAX(の正確な思想の前に F [12]、F [12-5] +4) 我々は、Fを発見した[12] = 8 <F [7] +5 = 11; 私達は「に」を選んだので、
    これはそれの最後ですので、私たちは三つの項目を持っている12の容量をカウントダウンし続けることは無駄です最大値は11だった。
    ここでも終わっ説明するために、反復アルゴリズム!

    ゴシップ

    最初にこのブログを書いて、私は論理的なエラーやバグがあるかもしれない、自分自身の理解によると、この内容が書かれている、最も重要なことは、彼らのレビューの知識は、ここに学んだ作るためにまだある、非常に興味深い感じ、問題はまだ見つかった場合コメントを助言してください。

    完全なコードは、私のGitHubを参照してください。

おすすめ

転載: www.cnblogs.com/sjh001/p/12041686.html