動態規劃-01揹包問題

狼爺發表於2021-02-14

01揹包

01揹包問題

有N件物品和一個容量為V的揹包。第i件物品的體積是c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。
從這個題目中可以看出,01揹包的特點就是:每種物品僅有一件,可以選擇放或不放。
其狀態轉移方程是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

填表

要理解上面的那個公式,需要學會填表。
假設

n=5, C=13, w={4,5,4,3,10}, v={9,10,9,2,24}

  • P[2,5]的含義是考慮前兩個物品,裝體積為5 的價值是10,揹包體積就減少4,無法再裝下第一個物品。也可以放棄第二個物品裝第一個物品,價值是9,最大的是10。所以裝第二個物品。
  • P[2,9]的含義是考慮前兩個物品,裝體積為5 的價值是10,揹包體積就減少4,還能再裝下第一個物品價值是9,總價值是19.另一種情況是捨棄第二件物品,直接裝第一件物品價值是9,價值明顯是裝兩件時候的大。
  • P[3,8]的含義是若裝第三件物品價值加9,揹包容量減少4,問題就變成了P[2,4]查表就知道P[2,4]最大是價值9,所以總價值是18;另一種情況是捨棄第三件物品,問題就變成P[2,8],查表發現最大價值是10。10明顯沒有18大,所以最大價值就是18。
  • P[3,9]的含義是若裝第三件物品價值加9,揹包容量減少4,問題就變成了P[2,4]查表就知道P[2,4]最大是價值9,所以總價值是18;另一種情況是捨棄第三件物品,問題就變成P[2,9],查表發現最大價值是19。19比18 大,所以最大值是19。
  • P[3,13]的含義是若裝第三件物品價值加9,揹包容量減少4,問題就變成了P[2,9]查表就知道P[2,9]最大是價值19,所以總價值是28;另一種情況是捨棄第三件物品,問題就變成P[2,13],查表發現最大價值是19。28比19大,所以最大值是28。

公式說明

假如揹包要放第i件物品,
此時如果不放第i件物品,那麼問題就轉化為“前i-1件物品放入重量是w的揹包中”,價值為f[i-1,j];
如果放第i件物品,那麼問題就轉化為“前i-1件物品放入剩下的重量為j-Wi的揹包中”,此時能獲得的最大價值就是f[i-1,j-Wi]再加上通過放入第i件物品獲得的價值Pi,此時只要比較f[i-1,j]和f[i-1,j-Wi]+Pi那個大就能獲取到揹包裡最大的價值是多少了。

程式碼

public class Test {
    public static int getMaxValue(int[] weight, int[] value, int w, int n) {
    	// 建立一個二維陣列,橫列是物品的價值,豎列是物品的重量
        int[][] table = new int[n + 1][w + 1];
        for (int i = 1; i <= n; i++) { //物品
            for (int j = 1; j <= w; j++) {  //揹包大小
                if (weight[i] > j) {
                    //當前物品i的重量比揹包容量j大,裝不下,肯定就是不裝
                    table[i][j] = table[i - 1][j];
                } else {
                	//裝得下,Max{裝物品i, 不裝物品i}
                    table[i][j] = Math.max(table[i - 1][j], table[i - 1][j - weight[i]] + value[i]);
                }
            }
        }
        return table[n][w];
    }

    public static void main(String[] args) {
        int n = 5, w = 13;                //物品個數,揹包容量
        int[] value = {0,9,10,9,2,24};    //各個物品的價值
        int[] weight = {0,4,5,4,3,10};    //各個物品的重量
        System.out.println(getMaxValue(weight, value, w, n));
    }
}

參考資料

相關文章