背包问题 0-1背包 完全背包 多重背包
区分
默认背包问题都先遍历物品(物品重量)再遍历背包(背包大小)但是不绝对 0-1背包问题遍历背包时逆序, 完全背包问题遍历背包时正序 求最大价值,dp初始值就小点(一般0就行),求最小价值,dp初始值就大点(找个数 Interger最大值或者背包大小+1W这种)
完全背包中 如果求组合数(顺序无关,1+5,5+1 算一种 循环中只会遍历到5+1)就是外层for循环遍历物品,内层for遍历背包。 如果求排列数(顺序相关,1+5,5+1 算两种,循环中1+5,5+1都会遍历到)就是外层for遍历背包,内层for循环遍历物品。
0-1背包是 一个背包里每个物品最多能放一次
完全背包是 一个背包里每个物品可以放多次
如果是求价值的最大值的往往递推公式是dp[j] = Math.max(dp[j],dp[j - weight[i]] + value[i]);这种每次把当前物品的重量减去再加上当前物品的价值
如果是求达到固定价值的方案个数的话往往递推公式是dp[j] += dp[j - coins[i]]; 这种求当前j背包重量下的方案个数,需要把dp[j](代表不考虑当前物品时的)+dp[j - coins[i]](代表考虑了当前物品并且有多少种方案加上当前物品正好能达到j这个背包容量(类似于爬楼梯))
多重背包就是在0-1背包的基础上,在循环内部在加一层循环这个物品数量的for循环。
0-1背包
https://kamacoder.com/problempage.php?pid=1046

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int M = sc.nextInt();
int N = sc.nextInt();
int[] weight = new int[M];
int[] value = new int[M];
for (int i = 0; i < M; i++) {
weight[i] = sc.nextInt();
}
for (int i = 0; i < M; i++) {
value[i] = sc.nextInt();
}
int[] dp = new int[N+1];
//且初始化全是0
for (int i = 0; i < M; i++) {//一共M个物品 挨个轮
for (int j = N; j >= weight[i] ; j--) {//逆序遍历 这个物品放进来没超上限时,就可以试试看合不合理,每次让背包上限--
dp[j] = Math.max(dp[j],dp[j - weight[i]] + value[i]);
}
}
System.out.println(dp[N]);
}
总结: dp[j]的含义是 用i以及i以前的物品去放的最大价值 j >= weight[i]说明j容量能放下i物品,那就判断不放i的时候和拿出来一个i的空去放i的时候哪个价值更高。 0-1背包遍历背包时逆序
完全背包
https://kamacoder.com/problempage.php?pid=1052

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int V = sc.nextInt();
int[] weight = new int[N];
int[] value = new int[N];
for (int i = 0; i < N; i++) {
weight[i] = sc.nextInt();
value[i] = sc.nextInt();
}
//初始值dp都为0 求最大价值,每一步用max,初始为小点
int[] dp = new int[V+1];
for (int i = 0; i < N; i++) {//一共N个物品。挨个轮
for (int j = weight[i]; j <= V ; j++) {//重量比背包上限小,就可以试试看放这个物品合不合理,每次让物品重量++
dp[j] = Math.max(dp[j],dp[j - weight[i]] + value[i]);
}
}
System.out.println(dp[V]);
}
总结: 完全背包问题,dp[j]代表用i物品以及i之前的物品去放的最大价值,,完全背包,所以遍历背包时正序。
多重背包
https://kamacoder.com/problempage.php?pid=1066

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int c = sc.nextInt();
int n = sc.nextInt();
int[] weight = new int[n];
int[] value = new int[n];
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
weight[i] = sc.nextInt();
}
for (int i = 0; i < n; i++) {
value[i] = sc.nextInt();
}
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
int[] dp = new int[c+1];
for (int i = 0; i < n; i++) {//遍历物品
for (int j = c; j >= weight[i] ; j--) {//遍历背包
//0-1背包的基础上加上一个遍历数量的操作
for (int k = 1; k <= nums[i]; k++) {
if (j - k * weight[i] >= 0){
dp[j] = Math.max(dp[j],dp[j-k*weight[i]] + k*value[i]);
}
}
}
}
System.out.println(dp[c]);
}
总结:完全背包就是在0-1背包的基础上加了一层遍历物品数量的操作。
浙公网安备 33010602011771号