题目解析
本文是一篇题解分享,对应题目是AI刷题板块的中等题-《0,1背包最大价值问题》。 问题简述如下:
将n件物品装入容量为m的背包,每件物品都有不同的重量weight和价值value,要求在不超过背包容量的情况下,使背包中物品的价值尽可能大。
思路分析
这是一个典型的01背包问题,解题思路是动态规划。每次考虑当天物品是否放入背包时,都需要考虑前面物品的取放情况,因此可以划归为动态规划的范畴。
关键代码
res[i][j] = Math.max(res[i - 1][j], res[i - 1][j - weights[i]] + values[i])
这道题的解法关键在于:判断第i件物品的时候,分两种情况考虑:该物品不放入背包,或者该物品放入背包。分别考虑两种情况的最大价值,选择最大的值作为当前物品的判断结果。
完整代码
public static int solution(int n, int[] weights, int[] values, int m) {
// 基本思路:动态规划
int[][] res = new int[n][m + 1];
// 状态转移方程 : 选择不装或者装的最大值
// res[i][j] = Math.max(res[i - 1][j], res[i - 1][j - weights[i]] + values[i])
// 初始化
for(int i = 0; i < n; i++){
res[i][0] = 0;
}
Arrays.fill(res[0], 0);
for(int j = weights[0]; j < m + 1; j++){
res[0][j] = values[0];
}
for(int i = 1; i < n; i++){
// 考虑第i个物品
for(int j = 1; j < m + 1; j++){
if(j >= weights[i]){ // 当前的容量足以放入第i件物品
res[i][j] = Math.max(res[i - 1][j], res[i - 1][j - weights[i]] + values[i]);
}
else{ // 当前的容量过小,不足以放入第i件物品
res[i][j] = res[i - 1][j];
}
}
}
return res[n - 1][m];
}
- 定义一个二维数组res,res[i][j]表示考虑第i件(0 ≤ i <n)物品,且背包容量为j(0 ≤ j ≤ m)时,所能得到的最大价值。
- 初始化数组:背包容量为0时,最大价值都为0;考虑第0件物品时,当背包容量大于等于第零件物品的重量,此时背包中物品的价值就是第0件物品的价值。
- 状态转移方程
res[i][j] = Math.max(res[i - 1][j], res[i - 1][j - weights[i]] + values[i])- 背包容量为j时,如果不放入第i件物品,此时背包最大的价值就是考虑第i - 1件物品且背包容量为j时能得到的最大价值
- 背包容量为j时,如果放入第i件物品,此时背包最大的价值是考虑第i - 1件物品且容量为(j - 当前物品的重量)时的最大价值
知识总结
当问题可以被分解为重叠子问题,并且这些子问题具有最优子结构时,动态规划是一个有效的解决方案。动态规划类的题目基本的解题步骤是:划分状态、确定边界条件以及推断状态转移方程。
该题目既可以考虑从动态规划的角度解题,也可以从贪心算法的角度去考虑。考虑到贪心算法并不总能得到最优解,因此本题从动态规划的角度出发。
学习计划
动态规划类的题目难度一般属于中等或者困难。背包问题属于常见的动态规划类题目,且有很多进阶问题,包括完全背包问题、多重背包问题等。解决这类问题最好是先从简单的01背包出发,通过观看视频或者阅读题解,学明白基本的01背包的基本思路后,举一反三,将其应用到其他题目上。
工具运用
- 刷题网站:leetocde / 牛客 / 稀土掘金AI刷题等
- 视频/博客:代码随想录 / 灵茶山艾府等
- AI:豆包Marscode AI等