LintCode 92:バックパック(クラシックタイトルバックパックDP)

  1. バックパック
    中文英語
    サイズ愛と考えるN項目は、整数mは、バックパックの大きさを表します。どのように完全なあなたは、このバックパックを埋めることができますか?

実施例
実施例1:
入力:[3,4,8,5]、バックパックのサイズ= 10
出力:9

実施例2:
入力:[2,3,5,7-]、バックパックのサイズ= 12
出力:12

チャレンジ
O(n×m個)時間とO(M)メモリ。

O(n×mの)メモリを使用すると、メモリを最適化する方法がわからない場合も可能です。

注意してください
あなたが小片に任意の項目を分割することはできません。

溶液1:二次元配列の
コードは以下の通りであります:

class Solution {
public:
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    int backPack(int m, vector<int> &A) {
        int n = A.size();
        vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
        
        for (int i = 1; i <= n; ++i) {
    //        for (int j = m; j >= A[i]; --j) {
          //  for (int j = A[i - 1]; j <= m; ++j) {
            for (int j = 1; j <= m; ++j) {    //也可以写成 for (int j = m; j >= 1; --j)
                if (j >= A[i - 1]) {
                    dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - A[i - 1]] + A[i - 1]);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[n][m];
    }
};

注意:

  1. ループのための第二は、jは1を起動する必要があります。書かれた
    ため(INT J = 1; J <= M; ++ j)を

    するため(INT J = M; J > = 1; --j)
    ことが可能です。
    なぜの書き込み(INT J = M; J > = 1; --j)? それは2サイクルであるので、それはの[J] [i]を計算DP、jは下降、または小から大にされているかどうか、であってもよいです場合、DP [I - 1] [ J - [I - 1]は、 I-1の内側前回のサイクルで算出されていなければなりません。

なく、
用(INT M = J; J> = A [I]; --j){
DP [I] [J] = MAX(DP [I - 1]〜[J]、DP [I - 1] [ J - A [I - 1]] + A [I - 1]);
}
書き込むことができない
。 - ; J <= M; J ++){1](INT J = A [Iため
DP [I] [J = MAX(DP [I - 1]〜[J]、DP [I - 1] [J - A [I - 1。。。]] + A [I - 1]);
}
DPとして[I] [0 ... A [ I]]これは常にゼロとなっています。
2)I、Jおよび2つのループの位置を交換することができるため。

方法2:最適化された1次元配列
コードは以下の通りであります:

class Solution {
public:
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    int backPack(int m, vector<int> &A) {
        int n = A.size();
        vector<int> dp(m + 1, 0);
        
        for (int i = 0; i < n; ++i) {
            for (int k = m; k >= A[i]; --k) {
            //for (int k = A[i]; k <= m; ++k) {    //wrong!!!
                dp[k] = max(dp[k], dp[k - A[i]] + A[i]);
            }
        }

        return dp[m];
    }
};

注:
1)ループの第二は、(int型K = A [iについて書き込むことができない ; K <= M; ++ K)]。なぜ?なぜなら
内部DP [K] = MAX(DP - + A [i]が[K]、DP [A [i]がK])は、実際と同等である
DP [I] [K] = MAX(DP [I - 1] [K]、DP [I - 1] [K - [I] + [I])
kが降順である場合、DP [k]を計算DP [K - [I] ] -確かに[[i]のK DP ] 前のラウンドで。
[ - A [i]がK kが大きいに小さい場合には、次にDPときに算出[k]をDP ]は、 DPの現在のラウンド[ - A [i]がKです ]。そして、その結果は右ではありません。
2)上記の文言と本質的に同等です

    int backPack(int m, vector<int> &A) {
        int n = A.size();
        vector<int> dp(m + 1, 0);
        
        for (int i = 0; i < n; ++i) {
            for (int k = m; k >= 0; --k) {
                if (k >= A[i])
                    dp[k] = max(dp[k], dp[k - A[i]] + A[i]);
                else
                    dp[k] = dp[k];
            }
        }

        return dp[m];
    }

しかしながら[K] = DP [K]余分な、第二サイクルに簡略化することができるDP

            for (int k = m; k >= A[i]; --k) {
                    dp[k] = max(dp[k], dp[k - A[i]] + A[i]);

おすすめ

転載: blog.csdn.net/roufoo/article/details/102996040