DP揹包之01揹包、完全揹包、多重揹包筆記
阿新 • • 發佈:2019-02-03
這是個經典話題,值得好好研究一番,本文作為學習筆記將會不斷更新。
主要參考了以下資料:
受益匪淺!
以下是Java的實現:
package DP; import java.util.Arrays; public class Knapsack01 { static int N = 3; // 物品個數 static int V = 5; //揹包最大容量 static int[] weight = {0,3,2,2}; //物品重量 static int[] value = {0,5,10,20}; //物品價值 static int[][] dp1 = new int[N+1][V+1]; public static void main(String[] args) { System.out.println(knapsack01_2D()); System.out.println(knapsack01_1D()); System.out.println(completeKnapsack()); System.out.println(multiKnapsack()); } /* 01揹包 目標:在不超過揹包容量的情況下,最多能獲得多少價值 子問題狀態:f[i][j]:表示前i件物品放入容量為j的揹包得到的最大價值 狀態轉移方程:f[i][j] = max{f[i - 1][j],f[i - 1][j - weight[i]] + value[i]} 初始化:f陣列全設定為0 */ public static int knapsack01_2D(){ //遞推 for(int i=1; i<=N; i++){ //列舉物品 for(int j=0; j<=V; j++){ //列舉揹包容量 dp1[i][j] = dp1[i-1][j]; if(j >= weight[i]){ dp1[i][j] = Math.max(dp1[i-1][j], dp1[i-1][j-weight[i]]+value[i]); } } } return dp1[N][V]; } //=============================== static int[] dp2 = new int[V+1]; /* 目標:在不超過揹包容量的情況下,最多能獲得多少價值 子問題狀態:f[j]:表示前i件物品放入容量為j的揹包得到的最大價值 狀態轉移方程:f[j] = max{f[j],f[j - weight[i]] + value[i]} 初始化:f陣列全設定為0 */ public static int knapsack01_1D(){ for(int i=1; i<=N; i++){ //列舉物品 for(int j=V; j>=weight[i]; j--){ //注意要逆序列舉容量!!! 防越界,j下限為 weight[i] dp2[j] = Math.max(dp2[j], dp2[j-weight[i]]+value[i]); } System.out.println(Arrays.toString(dp2)); } return dp2[V]; } /* 完全揹包 f[i][v]:前i件物品放入揹包容量為v的揹包獲得的最大收益 f[i][v] = max(f[i - 1][v],f[i - 1][v - k * Wi] + k * Vi,其中 1<=k<= v/Wi) 邊界條件 f[0][v] = 0; f[i][0] = 0; 總的複雜度為O(NV*Σ(V/c[i])) */ static int[][] dp3 = new int[N+1][V+1]; public static int completeKnapsack(){ for(int i=0; i<=N; i++){ dp3[i][0] = 0; } for(int v=0; v<=V; v++){ dp3[0][v] = 0; } for(int i=1; i<=N; i++){ for(int v=1; v<=V; v++){ dp3[i][v] = 0; int nCount = v / weight[i]; for(int k=0; k<=nCount; k++){ dp3[i][v] = Math.max(dp3[i][v], dp3[i-1][v-k*weight[i]]+k*value[i]); } } } return dp3[N][V]; } //===================================== /* 多重揹包 f[i][v]:表示把前i件物品放入容量為v的揹包中獲得的最大收益。 f[i][v] = max(f[i - 1][v],f[i - 1][v - k * Weight[i]] + K * Value[i]); 其中1 <= k <= min(Num[i],V/Weight[i]) 注意這裡受到Num[i]的約束 //初始化 f[i][0] = 0; f[0][v] = 0; */ static int[] num = {0,10,5,2}; //物品數量 static int[][] dp4 = new int[N+1][V+1]; public static int multiKnapsack(){ int nCount = 0; for(int i=0; i<=N; i++){ dp4[i][0] = 0; } for(int v=0; v<=V; v++){ dp4[0][v] = 0; } for(int i=1; i<=N; i++){ for(int v=1; v<=V; v++){ dp4[i][v] = 0; nCount = Math.min(num[i], v/weight[i]); for(int k=0; k<=nCount; k++){ dp4[i][v] = Math.max(dp4[i][4], dp4[i-1][v-k*weight[i]]+k*value[i]); } } } return dp4[N][V]; } }