揹包問題之完全揹包問題

問題描述:有n個物品,第 i 個物品的重量與價值分別爲 w[i]w[i]v[i]v[i]。揹包容量爲 V,試問在每個物品有無限個(物品必須保持完整)的情況下,如何讓揹包裝入的物品具有更大的價值總和。現有數據如下:

w = [2,3,4,5];
v = [3,4,5,6];
V = 10;

解題思路:令 dp[i][j]dp[i][j] 表示從編號 1~i 的物品中挑選任意數量的任意物品放入容量爲 j 的揹包中得到的最大價值,那麼有 dp[i][j]=max{dp[i1][jkw[i]]+kv[i]0k&kw[i]j}dp[i][j]=max\{dp[i-1][j-k*w[i]]+k*v[i]|0 \le k\&k*w[i] \le j\}。根據題意,在揹包容量不變的情況下,若增加意見物品仍然無法改變揹包內的物品,那麼最大價值仍然爲 dp[i1][j]dp[i-1][j],即 dp[i][j]=dp[i1][j]dp[i][j]= dp[i-1][j]。因此有 dp[i][j]=max{dp[i1][j],dp[i1][jkw[i]]+kv[i]0k&kw[i]j}dp[i][j]=max\{dp[i-1][j],dp[i-1][j-k*w[i]]+k*v[i]|0 \le k \&k*w[i] \le j\}

    public int knapsackProblem(int[] w, int[] v, int cap) {
        int[][] dp = new int[w.length + 1][cap + 1];
        for (int i = 1; i <= w.length; i++) {
            for (int j = cap; j > 0; j--) {
                dp[i][j] = dp[i - 1][j];
                for (int k = 0; k * w[i - 1] <= j; k++) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * w[i - 1]] + k * v[i - 1]);
                }
            }
        }
        return dp[w.length][cap];
    }

由以上代碼可知,時間複雜度爲 O(nV2)O(nV^2)

時間優化

dp[i][j]=max{dp[i1][j],dp[i1][jkw[i]]+kv[i]0k&kw[i]j}dp[i][j]=max\{dp[i-1][j],dp[i-1][j-k*w[i]]+k*v[i]|0 \le k\&k*w[i] \le j\}

dp[i][j]=max{dp[i1][j],max{dp[i1][(jw[i])(k1)w[i]]+(k1)v[i]0(k1)w[i]j}+v[i]}dp[i][j]=max\{dp[i-1][j], max\{dp[i-1][(j-w[i])-(k-1)*w[i]]+(k-1)*v[i]|0 \le (k-1)*w[i] \le j\} + v[i]\}

dp[i][j]=max{dp[i1][j],max{dp[i1][(jw[i])kw[i]]+kv[i]0k&(k+1)w[i]j}+v[i]}dp[i][j]=max\{dp[i-1][j], max\{dp[i-1][(j-w[i])-k*w[i]]+k*v[i]|0 \le k \& (k+1)*w[i] \le j\}+v[i]\}

縱觀上述表達式的第二項,有

dp[i][jw[i]]=max{dp[i1][(jw[i])kw[i]]+kv[i]0k&(k+1)v[i]j}dp[i][j-w[i]]=max\{dp[i-1][(j-w[i])-k*w[i]]+k*v[i]|0 \le k \& (k+1)*v[i] \le j\}

進而 dp[i][j]=max{dp[i1][j],dp[i][jw[i]]+v[i]}dp[i][j]=max\{dp[i-1][j], dp[i][j-w[i]]+v[i]\}

空間優化

dp[i][j]=max{dp[i1][j],dp[i][jw[i]]+v[i]}dp[i][j]=max\{dp[i-1][j], dp[i][j-w[i]]+v[i]\} => dp[j]=max{dp[j],dp[jw[i]]+v[i]},j=1,2,...capdp[j]=max\{dp[j], dp[j-w[i]]+v[i]\}, j=1,2,...cap

    public int knapsackProblem(int[] w, int[] v, int cap) {
        int[] dp = new int[cap + 1];
        for (int i = 0; i < w.length; i++) {
            for (int j = 1; j <= cap; j++) {
                if (w[i] <= j) {
                    dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
                }
            }
        }
        return dp[cap];
    }

時間複雜度爲 O(nV)O(nV)


上一篇:揹包問題之0-1揹包問題
下一篇:揹包問題之多重揹包問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章