问题分析:
0-1背包问题是一个经典的优化问题,其目标是在给定一系列物品和每个物品的价值及重量的条件下,选择物品放入背包,使得背包中物品的总价值最大,同时不超过背包的总承重。每个物品只能选择放入背包或不放入背包,因此称为0-1背包问题。0-1背包问题的求解思路主要基于动态规划。动态规划通过将问题分解为更小的子问题,并保存这些子问题的解以避免重复计算,从而高效地解决优化问题。
问题求解:
定义状态:
设 dp[ i ] [ j ] 表示考虑前 i 个物品,且背包容量为 j 时,能获得的最大价值。
状态转移方程:
对于第 i 个物品,有两种选择:放入背包或不放入背包。如果不放入第 i 个物品,则 dp[ i ] [ j ] = dp[ i-1 ] [ j ](即前 i-1 个物品在背包容量为 j 时的最大价值)。如果放入第 i 个物品,则dp[ i ] [ j ] = dp[ i-1 ] [ j-w[ i-1 ] ] + a[ i-1 ](即前 i-1 个物品在背包容量为 j-wt[ i-1 ] 时的最大价值加上第i个物品的价值,其中 w 是重量数组,a 是价值数组)。由于我们要找的是最大价值,所以 dp[ i ] [ j ] 应该是上述两种选择中的较大值。
同时,我们可以发现,第 i 行的最大价值只与第 i-1 行的的值有关,因此我们便可以考虑将数组压缩为一维数组。将数组压缩为一维数组后,我们可以看到第i轮的值会覆盖第 i-1 轮的值,但我们在计算状态转移方程,比较 dp[ j ] 和 dp[ j-w[ i-1 ] ] + a[ i-1 ] 时又会用到被覆盖了 dp[ j-w[ i-1 ] ] ,因此我们可以考虑进行反向遍历,这样就不会覆盖第 i-1 轮比现在背包容量小的值。
import java.util.Scanner;
public class main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
// 初始化参数
System.out.print("请输入物品总数量");
int num = scan.nextInt();
System.out.print("请输入背包总承重");
int vol = scan.nextInt();
int[] w = new int[num]; // 各个物品的总量
int[] a = new int[num]; // 各个物品的价值
for (int i = 0;i < num;i++) {
System.out.print("请输入第" + (i+1) + "个物品的重量");
w[i] = scan.nextInt();
}
for (int i = 0;i < num;i++) {
System.out.print("请输入第" + (i+1) + "个物品的价值");
a[i] = scan.nextInt();
}
int[] dp = new int[vol+1]; // 各个容量最大价值
// 每次取出一个物品,看不装下和能装下时哪个价值高
for (int i = 0;i < num;i++) {
for (int j = vol;j >= w[i];j--) {
dp[j] = Math.max(dp[j], dp[j-w[i]] + a[i]);
}
}
System.out.print("能获取的最大价值为:" + dp[vol]);
scan.close();
}
}
运行结果:
请输入物品总数量5
请输入背包总承重10
请输入第1个物品的重量1
请输入第2个物品的重量4
请输入第3个物品的重量2
请输入第4个物品的重量5
请输入第5个物品的重量2
请输入第1个物品的价值1
请输入第2个物品的价值6
请输入第3个物品的价值5
请输入第4个物品的价值3
请输入第5个物品的价值1
能获取的最大价值为:13