现有 n 个物品,第 i 个物品的体积为 vi , 重量为 wi
求当前背包最多能装多大重量的物品?
数据范围:
,
,
,
进阶 :
10,2,[[1,3],[10,4]]
4
第一个物品的体积为1,重量为3,第二个物品的体积为10,重量为4。只取第二个物品可以达到最优方案,取物重量为4
10,2,[[1,3],[9,8]]
11
两个物品体积之和等于背包能装的体积,所以两个物品都取是最优方案
// define dp[i][j]
int[][] dp = new int[n][V+1];
// init
for(int i=0;i<n;i++){
dp[i][0] = 0;//背包重量0放不了东西
}
for(int j = 0;j<=V;j++){
// 如果j大于等于物品的重量才能初始化为物品的价值
dp[0][j] = j>=vw[0][0]?vw[0][1]:0;
} //遍历
for(int i = 1;i<n;i++){
for(int j = 0;j<=V;j++){
if(j < vw[i][0]){// 放不了i,只能取前一个
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-vw[i][0]]+vw[i][1]);
}
}
} 5. 确定出口。就是dp最后一个元素还有对应的体积。就是 import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算01背包问题的结果
* @param V int整型 背包的体积
* @param n int整型 物品的个数
* @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
* @return int整型
*/
public int knapsack (int V, int n, int[][] vw) {
// write code here
// define dp[i][j]
int[][] dp = new int[n][V+1];
// init
for(int i=0;i<n;i++){
dp[i][0] = 0;//背包重量0放不了东西
}
for(int j = 0;j<=V;j++){
// 如果j大于等于物品的重量才能初始化为物品的价值
dp[0][j] = j>=vw[0][0]?vw[0][1]:0;
}
//遍历
for(int i = 1;i<n;i++){
for(int j = 0;j<=V;j++){
if(j < vw[i][0]){// 放不了i,只能取前一个
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-vw[i][0]]+vw[i][1]);
}
}
}
int r = dp[n-1][V];
System.out.print(r);
return r;
}
} public class Solution {
public int knapsack (int V, int n, int[][] vw) {
return process(vw,0,0,0,V,n);
}
public int process(int[][] vw,int i,int alreadyW,int alreadyV,int V,int n) {
if(alreadyV>V) {
return 0;
}
if(i==n) {
return alreadyW;
}
return Math.max(process(vw,i+1,alreadyW,alreadyV,V,n),
process(vw,i+1,alreadyW+vw[i][1],alreadyV+vw[i][0],V,n));
}
}
试试递归,超时🌶
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算01背包问题的结果
* @param V int整型 背包的体积
* @param n int整型 物品的个数
* @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
* @return int整型
*/
public int knapsack (int V, int n, int[][] vw) {
// write code here
int[][] dp = new int[n+1][V+1];
for(int i = 1 ; i <= n;i++){
for(int j = 1;j <= V;j++){
if(j < vw[i-1][0]){
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-vw[i-1][0]]+vw[i-1][1]);
}
}
}
return dp[n][V];
}
} import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算01背包问题的结果
* @param V int整型 背包的体积
* @param n int整型 物品的个数
* @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
* @return int整型
*/
public int knapsack2(int V, int n, int[][] vw) {
if (V <= 0 || n <= 0 || vw.length != n) {
return -1;
}
int[][] w = new int[n + 1][V + 1];
for (int i = n - 1; i >= 0; --i) {
for (int j = 1; j <= V; ++j) {
if (vw[i][0] <= j) {
w[i][j] = Math.max(w[i + 1][j - vw[i][0]] + vw[i][1], w[i + 1][j]);
} else {
w[i][j] = w[i + 1][j];
}
}
}
return w[0][V];
}
public int knapsack(int V, int n, int[][] vw) {
if (V <= 0 || n <= 0 || vw.length != n) {
return -1;
}
int[] w = new int[V + 1];
for (int i = 0; i < n; ++i) {
for (int j = V; j >= 1; --j) {
if (vw[i][0] <= j) {
w[j] = Math.max(w[j - vw[i][0]] + vw[i][1], w[j]);
}
}
}
return w[V];
}
} import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算01背包问题的结果
* @param V int整型 背包的体积
* @param n int整型 物品的个数
* @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
* @return int整型
*/
public int knapsack (int V, int n, int[][] vw) {
// write code here
if (V == 0 || n == 0) {
return 0;
}
int[][] dp = new int[V + 1][n + 1];
for (int i = 1; i <= V; i++) {
for (int j = 1; j <= n; j++) {
if (vw[j - 1][0] <= i) {
dp[i][j] = Math.max(dp[i - vw[j - 1][0]][j - 1] + vw[j - 1][1], dp[i][j - 1]);
} else {
dp[i][j] = dp[i][j - 1];
}
}
}
return dp[V][n];
}
} import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算01背包问题的结果
* @param V int整型 背包的体积
* @param n int整型 物品的个数
* @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
* @return int整型
*/
public int knapsack (int V, int n, int[][] vw) {
// write code here
// 备注 1 参考文章 https://cloud.tencent.com/developer/article/1574605
// 备注 2 vw 的索引范围, vw[0,199][0,1]
// 数组范围 +1, 简化代码, 比如不用 return dp[n-1][V-1], 且由于循环从 1 开始后续的 dp[i-1][j] 不用担心当 i==0 的时候 dp[-1][j] 会数组越界
int dp[][] = new int[n+1][V+1];
// 背包可容纳前 i (数量区间为[0,i]) 物品数量的最大(重量/价值)
for(int i=1; i<=n; i++){
// 背包最大可容纳体积为 j
for(int j=1; j<=V; j++){
// 先获取背包可容纳前 i-1 (数量区间为[0,i-1]) 物品数量的最大(重量/价值)
int oldMax = dp[i-1][j];
// 新的物品的体积
int iV = vw[i-1][0];
// 新的物品的(重量/价值)
int iW = vw[i-1][1];
// 如果新的物品的体积可以被背包容纳
if(j >= iV){
// 先计算好当体积为 j(当前背包最大可容纳体积) - iV(新的物品的体积) 时 背包可容纳前 i-1 (数量区间为[0,i-1]) 物品数量的最大(重量/价值)(已经在之前的步骤中计算好, 因为 0 < iV <= j, 所以 dp[i-1][j-iV] 已知)
// 然后 + iW(新的物品的(重量/价值))
// 即可得到 背包可容纳前 i (数量区间为[0,i]) 物品数量的最大(重量/价值)
int value = dp[i-1][j-iV] + iW;
// 取最大值
if(value > oldMax){
dp[i][j] = value;
}else{
// 说明性价比不高, 之前存在(重量/价值)较大且体积较小的物品
dp[i][j] = oldMax;
}
}else{
// 新的物品体积无法被背包容纳, 则背包可容纳的前i个物品数量的最大(重量/价值)等同于前i-1, 直接赋值
dp[i][j] = oldMax;
}
}
}
return dp[n][V];
}
}
// dp[i][j]表示:对于前i个物品,当前背包的容量为j时,这种情况下可以装下的最大价值是dp[i][j]。
// 如果你没有把这第i个物品装入背包,那么很显然,最大价值dp[i][j]应该等于dp[i-1][j]。
// 你不装嘛,那就继承之前的结果。
// 如果你把这第i个物品装入了背包,那么dp[i][j]应该等于
// dp[i-1] [ j-vm[j-vm[i-1][0] ] + vm[i-1][1]。但还是需要和不装入进行大小比较,取价值最大的。
import java.util.*;
public class Solution {
public int knapsack (int V, int n, int[][] vw) {
int v=V;
int[][]dp=new int[n+1][v+1];
for(int i = 1; i<=n;i++){
for(int j = 1;j<=v;j++){
if(j<vw[i-1][0]){//注意此处为i-1
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-vw[i-1][0]]+vw[i-1][1]);
}
}
}return dp[n][v];
}
}