[01]学習アルゴリズムナップザック問題

動的計画 - ソースのアルゴリズムは、実用的なコースムークラスのネットワークであり、

01ナップザック問題

01バックパック
これは、n個のアイテムの組み合わせを求めると同等です!
暴力ソリューション:
各項目は、あなたがバックパックに置くことができ、あなたが置くことができません。複雑さはO((2 ^ n)の*で N)、 各組み合わせについて、我々は、それがより多くの容量Cよりも大きいかどうかを確認するためにどのくらいの総重量に相当する参照しなければならないので、その値。

組み合わせは、再帰的にすることで解決することができます。しかし、変換がDPとなる、重なり合う部分問題、最適なサブ構造を見つけることができます。

デザイン:
状況:使用前の状態に問題を解決するためのパラメータは、問題は通常、制約が満たされる問題のニーズを解決することをパラメータ手段の数です。
この問題は2つの制約、選挙におけるn個のアイテムから第一、及び従って満たし≤C、その後に容量:状態(機能)である
F(N、C)考慮NアイテムバックパックCの容量、その結果の最大値。

状態遷移 F(I、C)= F(I-1、C):
上記項目I-1番目の考慮= V(I)+ F(I-1、CW(i))を
I TH用かバックパックに入れても、エンド記事では、2つのいずれかを選択し、最大
の状態遷移式 F(I、C)= MAX(F(I-1、C)、V(I)+ F(I-1を、 CWは、(i)))
動的計画の多くは、上記の考え方に似て使用することができます!

書き込みコード:まだ最初のトップダウン、ボトムアップし、その後に変身
再帰的に:

class 
Knapsack01 {
private:
    // 用[0,...index]的物品,来填充容积为c的背包的最大值
    int bestValue(const vector<int> &w, const vector<int> &v, int index, int c){

        // 无法选物品 or 装不下物品,都无价值
        if(index < 0 || c<=0)  
            return 0;

        int res = bestValue( w, v, index-1, c);
        // 检查一下容积C
        if( c >= w[index])
            res = max(res, v[index] + bestValue(w,v,index-1, c-w[index]) );

        return res;
    }

public:
    int knapsack01(const vector<int> &w, const vector<int> &v, int C ){

        int n = w.size();

        return bestValue(w, v, n-1, C); //考虑从0-n-1的n个物品,装入C
    }
    
};

:再帰メモリ検索+用いて
フォーマット
重複部分問題:指数cおよびデータを構成する、そのようなデータは、溶液プロセス中にこのメモリを検索するために使用することができる、複数回同じデータを解決するための方法であってもよいです。
2つの制約ナップサック問題があるため、各状態は二つの変数として定義され、オープンスペースは、メモリの2次元配列であります!-ベクトル<ベクトル>メモ(N、ベクター(C + 1、-1));
メモが有するN行、各行は、Vector、C + 1列の合計であります

private:
    vector<vector<int>> memo;
    // 用[0,...index]的物品,来填充容积为c的背包的最大值
    int bestValue(const vector<int> &w, const vector<int> &v, int index, int c){

        // 先判断有无值
        if(memo[index][c] != -1)
            return memo[index][c];

        // 无法选物品 or 装不下物品,都无价值
        if(index < 0 || c<=0)  
            return 0;

        for(int i=, i>=0; --i)
            for( int j=1; j<c; ++j ){
                memo[i] + ;
            }

        int res = bestValue( w, v, index-1, c);
        if( c >= w[index])
            res = max(res, v[index] + bestValue(w,v,index-1, c-w[index]) ); // 这里又重叠子问题了
        
        memo[index][c] = res;
        return res;
    }

動的計画:

ここに画像を挿入説明ここに画像を挿入説明

int knapsack01(const vector<int> &w, const vector<int> &v, int C ){

        assert(v.zise() == w.size()); // 判断一下
        int n = w.size();
        if(n==0)
            return 0;

        memo = vector<vector<int>>(n, vector<int>(C+1, -1)); //memo有n行,每一行都是一个vector<int>,一共有C+1列

        for(int j=0; j<=C; ++j)
            memo[0][j] = ( j >= w[0] ? v[0] : 0 );  //j是此时背包的容量
        
        for(int i=1; i<n; ++i)
            for(int j=0; j<=C; ++j){  

                memo[i][j] = memo[i-1][j];
                if( w[i] <= j )  // 可用容量大
                    memo[i][j] = max(memo[i][j], v[i]+memo[i-1][j-w[i] ] );
            }

        return memo[n-1][C];
    }
    

01バックパック複雑:
時間複雑:O(N C)
複雑容量:O(N
C)
最適化スペース:非常に短い時間、大空間-空間の最適化

最適化01ナップザック問題:
状態遷移方程式:F(I、C)= MAX(F(I-1、C)、V(I)+ F(I-1、CW(I)))
、i行目の要素のみI-1行目の要素に依存します。理論的には、要素の2行を維持するための唯一の必要性。したがって、空間複雑になる:O(2 * C)≈O (C)
ここに画像を挿入説明
偶数ライン処理上、次の奇数ライン処理。

int knapsack01(const vector<int> &w, const vector<int> &v, int C ){

        assert(v.zise() == w.size()); // 判断一下
        int n = w.size();
        if(n==0)
            return 0;

        memo = vector<vector<int>>(2, vector<int>(C+1, -1)); //memo有n行,每一行都是一个vector<int>,一共有C+1列

        for(int j=0; j<=C; ++j)
            memo[0][j] = ( j >= w[0] ? v[0] : 0 );  //j是此时背包的容量
        
        for(int i=1; i<n; ++i)
            for(int j=0; j<=C; ++j){  

                memo[i%2][j] = memo[(i-1)%2][j];
                if( w[i] <= j )  // 可用容量大
                    memo[i%2][j] = max(memo[i%2][j], v[i]+memo[(i-1)%2][j-w[i] ] );
            }

        return memo[(n-1)%2][C];
    }
    

さらなる最適化!
だからDPを完了するためにC配列のための唯一の1行
ここに画像を挿入説明
の行のために:常に左の上とに要素のみを使用し、右側の要素には触れません!
こうしてコンテンツをリフレッシュするためにのみ必要- -したがって、唯一のライン場合、現在の値と右から左へ以前の内容を見て、すなわちから:C = 5,4、... 1,0
グリッドがある場合、負荷容量が不足しています現在の記事の下で、その後、項目の前にこの容量が配置されていません!我々は入れてオリジナルのアイテムを使用する必要があります。このアルゴリズムはまた、いくつかの時空間複雑さの早期終了はの数を減らすことができるように〜

int knapsack01(const vector<int> &w, const vector<int> &v, int C ){

        assert(v.zise() == w.size()); // 判断一下
        int n = w.size();
        if(n==0)
            return 0;

        vector<int> memo(C+1, -1); //memo有n行,每一行都是一个vector<int>,一共有C+1列

        for(int j=0; j<=C; ++j)
            memo[j] = ( j >= w[0] ? v[0] : 0 );  //j是此时背包的容量
        
        for(int i=1; i<n; ++i)
            for(int j=C; j>=w[i]; --j){   // 条件是j>w[i]
                  // 可用容量大
                memo[j] = max(memo[j], v[i] + memo[j-w[i]] );
            }

        return memo[C];
    }

01バックパックは、バリアント:
完全なナップザック問題を:各項目-無制限の使用
ので、実際には各項目の番号を取得することができます(各項目が無制限で使用することができますが、しかしバックパックの限られた容量は、最大です!
=== >そう無制限の使用アイテムナップサック問題は少しナップザック問題で変換する-で選択した項目のリストに)使用アイテムが、多くのアイテムが重複があります
大容量のバックパックのために最適化:(際の良い最適化のアイデア)任意の数のために、バイナリコードを表すために使用することができるので、同じアイテムのため、必ずしもリスト1に追加されず、124816ような配列を追加して、撮影したアイテムの同じ数を表します。

複数のバックパック:複数の物品のそれぞれがNUM(I)番目の
複数のバックパックは、簡単です

主に手数料ナップザック問題:2次元でのアイテムのサイズと重量を考慮すべき!(すなわち、3次元配列)の
記事を加え複数の制約:物品との間には、相互に排他的であってもよく、相互に依存してもよいです

公開された63元の記事 ウォン称賛13 ビュー40000 +

おすすめ

転載: blog.csdn.net/changreal/article/details/102557271