6、實驗五0-1揹包問題
實驗內容
內容:給定n種物品和一個揹包,物品i價值wi和重量vi已知,確定裝入揹包的物品方案,使得包內物品總價值最大。
解題思路
原則:面對每個物品,只有選擇拿與不拿兩種選擇,不能夠選擇裝入物品的一部分,也不能裝入同一物品多次。
解決方法:聲明一個二維數組F[N + 1 , V + 1] ,F[i][v] 表示前i件物品恰放入一個容量恰爲v的揹包可以獲得的最大價值。通過分析可得出F[i , v]的計算方法,
1)當 v < W[i] 時,說明揹包容量不足以放下第i件物品,只能選擇不拿,此時:
2)當 v >= W[i] 時,這是揹包容量可以放下第i件物品,可以選擇拿還是不拿,判斷標準:拿這件物品是否能獲取更大的價值。
如果拿,則
如果不拿,則
源代碼
package e動態規劃求解0_1揹包;
import java.util.Scanner;
public class Zero_oneKnapsack {
int N, V;// N表示物體的個數,V表示揹包的載重
private int[] weight;// 用於存儲每個物體的重量,下標從1開始
private int[] value;// 存儲每個物體的收益,下標從1開始
private int[][] F;// 二維數組,用來保存每種狀態下的最大收益
public static void main(String[] args) {
Zero_oneKnapsack zok = new Zero_oneKnapsack();
zok.init();
zok.ZeroOnePackNonRecursive();
zok.printResult(zok.N, zok.V);
}
/**
* @see 求解F這個二位數組
*/
public void ZeroOnePackNonRecursive() {
// 對二維數組F進行初始化
for (int j = 0; j <= V; j++) {
F[0][j] = 0;
}
// 注意邊界問題,i是從1開始的,j是從0開始的
// 因爲F[i - 1][j]中i要減1
for (int i = 1; i <= N; i++) {
for (int j = 0; j <= V; j++) {
// 如果容量爲j的揹包放得下第i個物體
if (j >= weight[i]) {
F[i][j] = Math.max(F[i - 1][j - weight[i]] + value[i], F[i - 1][j]);
} else {
// 放不下,只能選擇不放第i個物體
F[i][j] = F[i - 1][j];
}
}
}
// 打印所有結果,我們要求的是F[N][V]
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= V; j++) {
System.out.print(F[i][j] + "\t");
}
System.out.println();
}
}
/**
* @see 求解F[n][m]這個最優值具體選取哪幾樣物品能獲得最大價值
* @param n 表示前n個物體,n <= N
* @param v 表示揹包的容量,v <= V
*/
public void printResult(int n, int v) {
boolean[] isAdd = new boolean[n + 1];
for (int i = n; i >= 1; i--) {
if (F[i][v] == F[i - 1][v])
isAdd[i] = false;
else {
isAdd[i] = true;
v -= weight[i];
}
}
for (int i = 1; i <= n; i++) {
if (isAdd[i] == true) {
System.out.println("揹包裏面有第 " + i + " 號物品");
}
}
System.out.println("最優結果是:" + F[N][V]);
}
/**
* @see 初始化
*/
public void init() {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入物體個數、揹包的總空間:");
N = sc.nextInt();
V = sc.nextInt();
// 下標從1開始,表示第1個物品
weight = new int[N + 1];
value = new int[N + 1];
F = new int[N + 1][V + 1];// 注意是 N + 1,因爲需要一個初始狀態F[0][0],表示前0個物品放進空間爲0的揹包的最大收益
System.out.println("請依次輸入每個物體的空間:");
for (int i = 1; i <= N; i++) {
weight[i] = sc.nextInt();
}
System.out.println("請依次輸入每個物體的價值:");
for (int i = 1; i <= N; i++) {
value[i] = sc.nextInt();
}
}
}