背包理论基础
视频地址: 带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili
01背包问题 二维
题目我是在Acwing上面做的,思路可以参照上面理论基础说的01背包,题目如下:
AC代码如下:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int v = scanner.nextInt();
int[] value = new int[n];
int[] weight = new int[n];
for(int i = 0;i < n;i++){
weight[i] = scanner.nextInt();
value[i] = scanner.nextInt();
}
int[][] dp = new int[n][v + 1];
for(int i = weight[0];i <= v;i++) dp[0][i] = value[0];
for(int i = 1;i < n;i++){
for(int j = 1;j <= v;j++){
// 处理一下背包放不下的情况
if(weight[i] > j ){
dp[i][j] = dp[i - 1][j];
continue;
}
dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - weight[i]] + value[i]);
}
}
System.out.print(dp[n - 1][v]);
}
}
01背包问题 一维
题目跟上面的是一样的,看题解:代码随想录
转成一维之后,我比较困惑的点就是为什么要倒着遍历...
因为怕dp[v]之后就不会更新了,那岂不是就找不到最大的了,
手动模拟一遍发现还是自己多虑了,逆着是为了不会重复取到一个物品,因为dp[j]已经保存了i - 1的最大值,所以只要考虑要不要加元素,后面的思路跟二维的这个是一样的。
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int v = scanner.nextInt();
int[] value = new int[n];
int[] weight = new int[n];
for(int i = 0;i < n;i++){
weight[i] = scanner.nextInt();
value[i] = scanner.nextInt();
}
int[] dp = new int[v + 1];
// for(int i = weight[0];i <= v;i++) dp[0][i] = value[0];
for(int i = 0;i < n;i++){
for(int j = v;j >= weight[i];j--){
// 处理一下背包放不下的情况
// if(weight[i] > j ){
// dp[i][j] = dp[i - 1][j];
// continue;
// }
dp[j] = Math.max(dp[j],dp[j - weight[i]] + value[i]);
}
}
System.out.print(dp[v]);
}
}
416. 分割等和子集
思路:先判断和是否为偶数,如果不是就返回false,剩下的部分用回溯做,只需要找到一组数等于sum/2就可以了,但是,超时了┭┮﹏┭┮,背包的确实没思路~,看题解:代码随想录
分析了一下,想不到用背包,主要是因为背包一般都是用来求最大值的,比如给定体积,求能装的价值最大,而这里是要判断是否可以找到一组数的和等于target。
但是这个问题也可以转换一下,就很🐂,转化的思路最关键的一点就是:对于容量为target的背包,我们要找这么一组数的和为target,其实也就是在求容量为target的包能装的最大价值,因为这里value = weight,所以dp[target]的最大值也就是target。
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for(int i = 0;i < nums.length;i++)
sum += nums[i];
if(sum % 2 == 1)
return false;
//
int target = sum / 2;
int[] dp = new int[target + 1];
for(int i = 0;i < nums.length;i++){
for(int j = target;j >= nums[i];j--){
dp[j] = Math.max(dp[j],dp[j - nums[i]] + nums[i]);
}
if(dp[target] == target)
return true;
}
return dp[target] == target;
}
}