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();
}
}
}