01背包
01背包,是指在N个物品中,每个物品的体积为vi[i],每个物品的权重(价值)为wi[i]。怎么在体积为V的背包中,获得最大价值
且在01背包中,每件物品只有两种选法:选或是不选
注:本帖子中的所有内容,均以java代码进行演示
问题一:
点击题目,跳转到原题。
剖析:
用 v[i] 表示每件物品的体积,用 wi[i] 表示每件物品的权重(价值)
用 dp【i】【j】表示,对于第 i 件物品,在空间为j时,获得的最大价值。
因为,第0件物品,在任何空间下的价值都为0,所以可以不用做判断。
则可以从第1件物品,依次进行遍历,直到第 N 件物品时结束。
当前遍历到第 i 件物品时,若背包体积小于vi[i] ,则获得的最大价值与 dp【i-1】【j】相同。当背包的体积大于
vi[i]时,则分为两种情况。
情况一:选择第 i 件物品,则获得的价值为 dp【i-1】【j-vi[i]】+ wi[i]。
情况二:不选择第 i 件物品,则获得的价值为 dp【i-1】【j】
由此可以得出01背包的二维数组表示法:
说明:因为本题,需要自己主函数、输入、输出函数,故将该部分进行抽取如下:
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//scanner.next() 标准输出函数
//物品数量
int n = scanner.nextInt();
//最大体积
int v = scanner.nextInt();
//第i件物品所占的体积
int[] vi = new int[n + 1];
//第i件物品的权重
int[] wi = new int[n + 1];
// 接下来有 N 行,每行有两个整数:v[i],w[i],用空格隔开,分别表示第i件物品的体积和价值
for (int i = 1; i <= n; i++) {
vi[i] = scanner.nextInt();
wi[i] = scanner.nextInt();
}
//主要实现函数
oneTwoBackpacker(n, v, vi, wi);
}
}
01背包的二维数组表示法
//二维数组,表示法
private static void oneTwoBackpacker(int n, int v, int[] vi, int[] wi) {
int[][] dp = new int[n + 1][v + 1];
//从第一个物品,到第N个物品
for (int i = 1; i <= n; i++) {
//从0体积,到v体积
for (int j = 0; j <= v; j++) {
if (j >= vi[i])
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - vi[i]] + wi[i]);
else dp[i][j] = dp[i - 1][j];
}
}
System.out.println(dp[n][v]);
}
我们注意到,在求取 **dp【i】【j】**时,只使用到了 dp【i-1】【j】和dp【i-1】【j-vi[i]】,故可以利用滚动数组,对此进行优化。
但是如果直接将 dp 数组,降到一维的话,会出现一个问题,那就是在计算 dp[j] = Math.max(dp[j], dp[j - vi[i]] + wi[i]);
时,由于 j-vi[i] 小于 j,且我们的 j,是从小到大,进行遍历的。那就会造成一个问题,dp[j - vi[i]]!=dp[i - 1][j - vi[i]]
。因为 dp[i - 1][j - vi[i]]
,计算的是前 i-1 个物品(包含第 i-1 个物品),在体积为 j - vi[i] 时,所获得的最大价值。而 dp[j - vi[i]]
,计算的则是前 i 个物品(包含第 i 个物品),在体积为 j - vi[i] 时,所获得的最大价值
所以,我们如果要想使用滚动数组,优化01背包,就要解决这个问题。
其实,如果我们让 j ,从大到小,依次遍历的话,问题就解决了。因为在计算到 dp[j] = Math.max(dp[j], dp[j - vi[i]] + wi[i]);
时,由于 (j - vi[i])<j
,故当前用到的还是前i-1个物品的 dp[j - vi[i]
.
01背包的一维数组表示法
//一维数组优化
private static void oneTwoBackpacker(int n, int v, int[] vi, int[] wi) {
int[] dp = new int[v + 1];
//从第一个物品,到第N个物品
for (int i = 1; i <= n; i++) {
//从v体积到vi[i]体积
for (int j = v; j >= vi[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - vi[i]] + wi[i]);
}
}
System.out.println(dp[v]);
}
感谢您的阅读!