Day 35 贪心算法 Part03
- 携带研究材料(第六期模拟笔试)
这道题就是最标准的01背包问题,如果第一次见还是很难想出什么办法,用回溯(每个物品有选或不选两种状态,时间复杂度为$2^n$)暴力去做一定会超时。
import java.util.*;
public class Main{
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];
int[][] dp = new int[m][n+1];
for(int i = 0; i < m; i++) weight[i] = sc.nextInt();
for(int i = 0; i < m; i++) value[i] = sc.nextInt();
for(int j = weight[0]; j <= n; j++) dp[0][j] = value[0];
for(int i = 1; i < m; i++){
for(int j = 0; j <= n; j++){
if(j < weight[i]) dp[i][j] = dp[i-1][j];
else dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]);
}
}
System.out.println(dp[m-1][n]);
}
}
public class Main{ //滚动数组优化空间复杂度
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];
int[] dp = new int[n+1];
for(int i = 0; i < m; i++) weight[i] = sc.nextInt();
for(int i = 0; i < m; i++) value[i] = sc.nextInt();
for(int i = 0; i < m; i++)
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]);
}
}
416. 分割等和子集
就是告诉我是01背包,他也还是不好做啊。没办法,去看了题解才做出来。还是按照动态规划的题目套路来。
dp数组的含义:还是以2维数组来理解其含义(一维也是一致的,但二维更好讲清楚一些)。dp[i,j]代表了使用0-i间的任意物品组合,背包容量为j,所能装下的最大value。注意,对于本题,weight和value都是数字本身的值,背包总容量就是数组元素和的一半。- 理解
dp数组含义是这道题的重中之重。其实这道题就可以等价于,背包容量为数组元素和的一半,能否在给出的数字中,找到一部分其和恰好把背包填满。
class Solution {
public boolean canPartition(int[] nums) {
int sum = Arrays.stream(nums).sum();
if(sum % 2 != 0) return false;
sum /= 2;
int n = nums.length;
int[] dp = new int[sum+1];
for(int i = 0; i < n; i++)
for(int j = sum; j >= nums[i]; j--)
dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);
return dp[sum] == sum;
}
}

浙公网安备 33010602011771号