动态规划day03
作者:互联网
0/1背包滚动数组
题目:
代码:
package LeetCode;
import java.util.Arrays;
public class zero_one_bag {
public static void main(String[] args) {
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int maxWeight = 4;
testZeroOneBag02(weight, value, maxWeight);
}
//滚动数组
private static void testZeroOneBag02(int[] weight, int[] value, int maxWeight) {
int n = weight.length;
int[] dp = new int[maxWeight + 1];
for (int i = 0; i < n; i++) {
for (int j = maxWeight; j >= weight[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
}
}
System.out.println("物品重量:" + Arrays.toString(weight));
System.out.println("物品价值:" + Arrays.toString(value));
System.out.println("背包最大容重:" + maxWeight);
System.out.println("一维dp:" + Arrays.toString(dp));
System.out.println("可放入最大价值量:" + dp[maxWeight]);
}
}
运行结果:
416. 分割等和子集
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int n : nums) {
sum += n;
}
//总和为奇数,不能划分两个和相同的子集
if (sum % 2 == 1) return false;
//转化0/1背包问题,sum/2为背包容量,物品i重量和价值为nums[i]
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]);
}
}
return dp[target] == target;
}
}
1049. 最后一块石头的重量 II
class Solution {
public int lastStoneWeightII(int[] stones) {
int n = stones.length, sum = 0;
for (int w : stones) {
sum += w;
}
int target = sum / 2;
int[] dp = new int[target + 1];
//转化为背包问题,背包容量为sum/2,石头i重量和价值为stones[i]
for (int i = 0; i < n; i++) {
for (int j = target; j >= stones[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
//分成两堆,dp[target]最大值为sum/2, 则sum - dp[target] >= dp[target]
return sum - 2 * dp[target];
}
}
494. 目标和
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int n = nums.length, sum = 0;
for (int num : nums) {
sum += num;
}
//设正数和为x,x - (sum - x) = target为目标等式 <==> x = (target + sum) / 2;
//上述问题即找nums子集使之和为x,可转化为0/1背包问题,容重为x,物品i重量nums[i],与之前不同的是,以前是最大容量可装最大价值,现在是装满价值j有多少中方法
/*也就是求解组合问题,即和为x的子集有多少种。*/
//由以上分析,(target + sum) % 2 == 1 无解, sum < abs(target) 无解
if ((target + sum) % 2 == 1) return 0;
if (Math.abs(target) > sum) return 0;
int w = (target + sum) / 2;
int[] dp = new int[w + 1];
//递推式 dp[j] 共有dp[j - nums[i]]种方法,dp[0] = 1表示不装任何物品也是一种方法
dp[0] = 1;
for (int i = 0; i < n; i++) {
for (int j = w; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[w];
}
}
标签:stones,target,nums,day03,sum,int,动态,规划,dp 来源: https://www.cnblogs.com/lizihhh/p/dp_day03.html