[Java] 兩種方式實現動態規劃之 0-1 揹包問題

感謝 劉永輝從傑Arun-Manivannan 的幫助,及其他博主的算法解惑與代碼實現。因看目前博文的”0-1 揹包”實現較爲單一,故在此贅述總結。

方法一:

public class ZeroOnePack {
    public static void main(String[] args) throws Exception {
        int val[] = { 80, 72, 91, 33 };
        int wt[] = { 5, 4, 6, 3 };
        int W = 9;

        System.out.println(pack(val, wt, W));
    }

    public static int pack(int val[], int wt[], int W) {
        // 所能承最大值
        int len = val.length;
        int[][] maxArr = new int[len + 1][W + 1];

        // 最外層循環爲物品項
        for (int item = 1; item <= len; item++) {
            // 第二層爲仍有空閒空間下的情況
            for (int weight = 1; weight <= W; weight++) {
                // 當前物品的重量是否小於或等於總重
                if (wt[item - 1] <= weight) {
                    // weight - wt[item - 1] 就相當於刨去當前項的重量,在這個約束下求較大值
                    maxArr[item][weight] = Math.max(maxArr[item - 1][weight],
                            maxArr[item - 1][weight - wt[item - 1]] + val[item - 1]);
                } else {
                    maxArr[item][weight] = maxArr[item - 1][weight];
                }
            }
        }
        // Printing the matrix
        for (int[] rows : maxArr) {
            for (int col : rows) {
                System.out.format("%5d", col);
            }
            System.out.println();

        }
        return maxArr[len][W];
    }
}

方法二:

public class ZeroOnePackMy {
    /** 每個物品對應價值 */
    public static int val[] = { 80, 72, 91, 33 };
    /** 每個物品對應重量 */
    public static int wt[] = { 5, 4, 6, 3 };
    /** 袋子最大重量,數組編號從 0 開始 */
    public static int W = 10;
    /** 物品數量,數組編號從 0 開始 */
    public static int N = 4;
    /**
     * 指定編號和重量下,所存放的最大價值(編號有順序)<br />
     * 此處指定 W + 1 是 1.防止越界 2.取到邊界值情況
     */
    public static int[][] maxArr = new int[N][W + 1];

    public static void main(String[] args) throws Exception {

        System.out.println(maxPack(N - 1, W));

        for (int i = 0; i < maxArr.length; i++) {
            for (int j = 0; j < maxArr[0].length; j++) {
                int mVal = maxArr[i][j];
                System.out.format("%5d", mVal);
            }
            System.out.println();
        }
    }

    /**
     * 參照 http://www.cnblogs.com/sdjl/articles/1274312.html
     * 
     * @param n
     *            物品編號
     * @param w
     *            可放重量
     * @return
     */
    public static int maxPack(int n, int w) {
        // 此處可用 -1 作動態規劃中的 "備忘錄",需前面統一遍歷設置
        // if (maxArr[n][m] == -1) {}
        // 編號爲 0,即只有一個物品 [對應動態規劃中的 "邊界"]
        if (n == 0) {
            if (w >= wt[0]) {
                // 如果剩餘重量大於 0 號重量,就放進去,最大價值即 0 號價值
                maxArr[n][w] = val[0];
            } else {
                // 否則就放不下,此時最大價值爲 0
                maxArr[n][w] = 0;
            }
        } else {
            if (w >= wt[n]) {
                // 如果剩餘重量大於 n 號重量,就可以放進去 n 號或者放比 n 編號小的一些物品,並取出最大值
                // 此處遞歸實現
                maxArr[n][w] = Math.max(maxPack(n - 1, w), maxPack(n - 1, w - wt[n]) + val[n]);
            } else {
                // 否則就放不下,此時最大價值就看當前重量下比 n 編號小的物品了
                maxArr[n][w] = maxPack(n - 1, w);
            }
        }

        return maxArr[n][w];
    }
}

參考文章:
1. 動態規劃之 01 揹包問題(最易理解的講解)
2. 本週算法:揹包問題
3. The Knapsack problem
4. 通過金礦模型介紹動態規劃

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