当前位置:网站首页>动态规划之如何将问题抽象转化为0-1背包问题(详解利用动态规划求方案数)
动态规划之如何将问题抽象转化为0-1背包问题(详解利用动态规划求方案数)
2022-06-12 21:41:00 【InfoQ】
️如何将问题抽象为0-1背包️
最后一块石头的重量 II
stonesstones[i]ixyx <= y- 如果
x == y,那么两块石头都会被完全粉碎;
- 如果
x != y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。
0输入:stones = [2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
输入:stones = [31,26,33,21,40]
输出:5
1 <= stones.length <= 30
1 <= stones[i] <= 100
解题思路
+-+-aba>=ba-bcc-(a-b)a-b+d(a-b)-dabab+-+-+-+/-00+-+big_sum-small_sumbig_sum-small_sumsumsum=big_sum+small_sumbig_sum>=small_sumsmall_sum<=sum/2sum/2sumclass Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int x : stones) {
sum += x;
}
int ret = sum / 2;
int n = stones.length;
int[][] dp = new int[n+1][ret+1];
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= ret; j++) {
int x = dp[i-1][j];
int y = j >= stones[i-1] ? dp[i-1][j-stones[i-1]] + stones[i-1] : 0;
dp[i][j] = Math.max(x, y);
}
}
return sum - 2 * dp[n][ret];
}
}
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int x : stones) {
sum += x;
}
int ret = sum / 2;
int n = stones.length;
int[][] dp = new int[2][ret+1];
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= ret; j++) {
int index = (i-1) & 1;
int x = dp[index][j];
int y = j >= stones[i-1] ? dp[index][j-stones[i-1]] + stones[i-1] : 0;
dp[i&1][j] = Math.max(x, y);
}
}
return sum - 2 * dp[n&1][ret];
}
}
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int x : stones) {
sum += x;
}
int ret = sum / 2;
int n = stones.length;
int[] dp = new int[ret+1];
for (int i = 1; i <= n; i++) {
for (int j = ret; j >= stones[i-1]; j--) {
int x = stones[i-1];
dp[j] = Math.max(dp[j], dp[j-x]+x);
}
}
return sum - 2 * dp[ret];
}
}
练习:目标和
numstarget'+''-'- 例如,
nums = [2, 1],可以在2之前添加'+',在1之前添加'-',然后串联起来得到表达式"+2-1"。
target输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
输入:nums = [1], target = 1
输出:1
1 <= nums.length <= 20
0 <= nums[i] <= 1000
0 <= sum(nums[i]) <= 1000
-1000 <= target <= 1000
习题解答
nums+/-target0target1numss--s+s0j0+/-itclass Solution {
public int findTargetSumWays(int[] nums, int target) {
//动态规划
//状态转移方程dp[i][j] = dp[i-1][j-nums[i]] + dp[i-1][j+nums[i]]
//i表示数组前i个元素,j表示目标和,dp[i][j]表示从前i个元素中进行+/-得到j的方案数
//考虑极端情况,目标和最大取值为数组的元素绝对值之和记为s,最小值为-s,所以j的可能取值一共2s+1个
//1. 求数组元素绝对值的和
int s = 0;
for (int x : nums) {
s += Math.abs(x);
}
//如果target绝对值大于数组目标和的最大值,不可能存在合法的方案
if (Math.abs(target) > s) {
return 0;
}
//2. 创建动态规划数组
int len = nums.length;
int[][] dp = new int[len + 1][2 *s + 1];
//3. 初始化,0->-s,s->0
dp[0][s] = 1;
//4. 处理剩余情况
for (int i = 1; i <= len; i++) {
int t = nums[i - 1];
for (int j = -s; j <= s; j++) {
//当权重为+时,如果满足合法范围,加上dp[i - 1][j + s - t]
if (j + s - t >= 0) {
dp[i][j + s] += dp[i - 1][j + s - t];
}
//当权重为-时,如果满足合法范围,加上dp[i - 1][j + s + t]
if (j + s + t <= 2 * s) {
dp[i][j + s] += dp[i - 1][j + s + t];
}
}
}
return dp[len][target+s];
}
}
class Solution {
public int findTargetSumWays(int[] nums, int target) {
//动态规划
//状态转移方程dp[i][j] = dp[i-1][j-nums[i]] + dp[i-1][j+nums[i]]
//i表示数组前i个元素,j表示目标和,dp[i][j]表示从前i个元素中进行+/-得到j的方案数
//考虑极端情况,目标和最大取值为数组的元素绝对值之和记为s,最小值为-s,所以j的可能取值一共2s+1个
//1. 求数组元素绝对值的和
int s = 0;
for (int x : nums) {
s += Math.abs(x);
}
//如果target绝对值大于数组目标和的最大值,不可能存在合法的方案
if (Math.abs(target) > s) {
return 0;
}
//2. 创建动态规划数组
int len = nums.length;
int[][] dp = new int[2][2 *s + 1];
//3. 初始化,0->-s,s->0
dp[0][s] = 1;
//4. 处理剩余情况
for (int i = 1; i <= len; i++) {
int t = nums[i - 1];
for (int j = -s; j <= s; j++) {
//更新值时,需要对原来那一行的值归零
dp[i&1][j + s] = 0;
//如果满足左边界的值,加上dp[i - 1][j + s - t]
if (j + s - t >= 0) {
dp[i&1][j + s] += dp[(i-1)&1][j + s - t];
}
//如果满足右边界的值,加上dp[i - 1][j + s + t]
if (j + s + t <= 2 * s) {
dp[i&1][j + s] += dp[(i-1)&1][j + s + t];
}
}
}
return dp[len&1][target+s];
}
}
优化方案
class Solution {
public int findTargetSumWays(int[] nums, int target) {
//动态规划
//对于第i个元素,值为t,如果不选,则方案数dp[i-1][j],如果选择,则方案数dp[i-1][j-t],总方案数dp[i][j]=dp[i-1][j]+dp[i-1][j-t]。
//1. 求数组元素绝对值的和
int s = 0;
for (int x : nums) {
s += Math.abs(x);
}
int m = (s - target) / 2;
//如果target绝对值大于数组目标和的最大值,或者s-target不是偶数,不可能存在合法的方案
if (Math.abs(target) > s || (s - target) % 2 != 0) {
return 0;
}
//2. 创建动态规划数组,一维优化
int len = nums.length;
int[][] dp = new int[len+1][m+1];
//3. 初始化dp[0][0] = 1;
dp[0][0] = 1;
//4. 处理剩余情况
for (int i = 1; i <= len; i++) {
int t = nums[i - 1];
for (int j = 0; j <= m; j++) {
dp[i][j] = dp[i-1][j];
if (j >= t) {
dp[i][j] += dp[i-1][j-t];
}
}
}
return dp[len][m];
}
}
class Solution {
public int findTargetSumWays(int[] nums, int target) {
//动态规划
//对于第i个元素,值为t,如果不选,则方案数dp[i-1][j],如果选择,则方案数dp[i-1][j-t],总方案数dp[i][j]=dp[i-1][j]+dp[i-1][j-t]。
//1. 求数组元素绝对值的和
int s = 0;
for (int x : nums) {
s += Math.abs(x);
}
int m = (s - target) / 2;
//如果target绝对值大于数组目标和的最大值,或者s-target不是偶数,不可能存在合法的方案
if (Math.abs(target) > s || (s - target) % 2 != 0) {
return 0;
}
//2. 创建动态规划数组,一维优化
int len = nums.length;
int[][] dp = new int[2][m+1];
//3. 初始化dp[0][0] = 1;
dp[0][0] = 1;
//4. 处理剩余情况
for (int i = 1; i <= len; i++) {
int t = nums[i - 1];
for (int j = 0; j <= m; j++) {
dp[i&1][j] = dp[(i-1)&1][j];
if (j >= t) {
dp[i&1][j] += dp[(i-1)&1][j-t];
}
}
}
return dp[len&1][m];
}
}
class Solution {
public int findTargetSumWays(int[] nums, int target) {
//动态规划
//对于第i个元素,值为t,如果不选,则方案数dp[i-1][j],如果选择,则方案数dp[i-1][j-t],总方案数dp[i][j]=dp[i-1][j]+dp[i-1][j-t]。
//1. 求数组元素绝对值的和
int s = 0;
for (int x : nums) {
s += Math.abs(x);
}
int m = (s - target) / 2;
//如果target绝对值大于数组目标和的最大值,或者s-target不是偶数,不可能存在合法的方案
if (Math.abs(target) > s || (s - target) % 2 != 0) {
return 0;
}
//2. 创建动态规划数组,一维优化
int len = nums.length;
int[] dp = new int[m+1];
//3. 初始化dp[0] = 1;
dp[0] = 1;
//4. 处理剩余情况
for (int i = 1; i <= len; i++) {
int t = nums[i - 1];
for (int j = m; j >= t; j--) {
dp[j] += dp[j-t];
}
}
return dp[m];
}
}
边栏推荐
- Ubuntu 16.04 installing mysql5.6
- 在同花顺开户证券安全吗,证券开户怎么开户流程
- SQL tuning guide notes 12:configuring options for optimizer statistics gathering
- Graphics2d class basic use
- DRF receives nested data and creates objects. Solution: DRF not NULL constraint failed
- 六月集训(第11天) —— 矩阵
- Okio source code analysis
- ORM 实现类与表,类属性与字段的映射关系
- Gzip compression decompression
- Cookies and sessions
猜你喜欢

Deep Hough voting for 3D object detection in point clouds

如何自己动手写一个vscode插件,实现插件自由!

利用ADG Standby克隆PDB

Digital intelligence data depth | Bi goes down the altar? It's not that the market has declined, it's that the story has changed

Okio source code analysis

@loadbalance annotation of resttemplate

SQL调优指南笔记17:Importing and Exporting Optimizer Statistics

“Oracle数据库并行执行”技术白皮书读书笔记

SQL tuning guide notes 18:analyzing statistics using optimizer statistics Advisor

回文链表及链表相交问题(和心怡的人相交)你真的会了吗?
随机推荐
What is the race condition? How do you find and solve the competition?
SQL调优指南笔记6:Explaining and Displaying Execution Plans
有向图深拷贝
Semester summary of freshman year
zgc的垃圾收集的主要阶段
Libmysqlclient A static library
Shell script Basics
Two sentences to clarify JS throttling and anti shake
Vagrantbox reinstalling the vboxsf driver
DRF receives nested data and creates objects. Solution: DRF not NULL constraint failed
Rearrangement exercises
Test basis: unit test
What are thread scheduler and timeslicing?
Permission to query execution plan in Oracle Database
Graphics2d class basic use
JUC并发工具包使用指南
Ansible-大总结(六)
selenium操作元素遇到的异常
Kdd2022 | graphmae: self supervised mask map self encoder
The service did not report any errors MySQL