算法思想:動態規劃
實際問題:01揹包問題
編寫語言:Javajava
給定n種物品和一個揹包,物品i的重量爲wi,其價值是vi,揹包的容量爲c,問應如何向背包裝入物品,使得揹包中的物品價值最大。每一個物品拿取或者不拿兩種選擇。不能選擇裝入某物品的一部分,也不能裝入同一物品屢次。算法
聲明一個大小爲m[n][c]的二維數組,m[i][j]表示在面對第i件物品,且揹包容量爲j時所能得到的最大價值。則:數組
public class OneZeroKnapsackProblem { public static void main(String[] args) { //如下數組第0位(第0行,第0列)都不存儲數據 int[] v = new int[]{0, 8, 10, 6, 3, 7, 2}; //每件物品的價值 int[] w = new int[]{0, 4, 6, 2, 2, 5, 1}; //每件物品的重量 int c = 12; //揹包的容量 int n = v.length - 1; //物品的數量 int[][] m = new int[n + 1][c + 1]; //總價值數組 int[] r = new int[n + 1]; //構造最優解的數組 for(int i = 0; i <= n; i++) { for(int j = 0; j <= c; j++) m[i][j] = 0; r[i] = 0; } knapsack(v, w, c, n, m); traceback(m, w, c, n, r); System.out.println("物品數量爲 " + n + " ,揹包容量爲 " + c); System.out.print("各個物品的價值爲:"); for(int i = 1; i <= n; i++) { System.out.print(v[i] + " "); } System.out.println(); System.out.print("各個物品的重量爲:"); for(int i = 1; i <= n; i++) { System.out.print(w[i] + " "); } System.out.println(); System.out.println("最多價值爲:" + m[n][c]); System.out.print("放入的物品爲:"); for(int i = 1; i <= n; i++) System.out.print(r[i] + " "); System.out.println(); } /** * 該方法計算最優解: * @param v 存儲每一個物品的價值 * @param w 存儲每一個物品的重量 * @param c 存儲揹包容量 * @param n 物品數量 * @param m 存儲構造的最優解 */ public static void knapsack(int[] v, int[] w, int c, int n, int[][] m) { //物品從第1件物品開始計算 for(int i = 1; i <= n; i++) { for(int j = 1; j <= c; j++) { if(j >= w[i]) { m[i][j] = max(m[i - 1][j], m[i - 1][j - w[i]] + v[i]); } else { m[i][j] = m[i - 1][j]; } } } } /** * 該方法構造最優解的生成過程: * @param m 存儲最優解的數組 * @param w 存儲每一個物品的重量 * @param c 存儲揹包容量 * @param n 物品數量 * @param x 存儲最優解生成過程的數組 */ public static void traceback(int[][] m, int[] w, int c, int n, int[] x) { for(int i = 1; i <= n; i++) { if(m[i][c] == m[i - 1][c]) //第i件物品爲未放入 { x[i] = 0; } else //第i件放入 { x[i] = 1; c -= w[i]; } } } public static int max(int a, int b) { return a > b ? a : b; } }