第五章 动态规划
分享关于动态规划方面的讲解博客或者题解报告
MangataTS
一个爱折腾的Coder
展开
-
AcWing 901. 滑雪(记忆化搜索)
题目链接https://www.acwing.com/problem/content/903/思路我们定义f[i][j]f[i][j]f[i][j]表示以(i,j)(i,j)(i,j)作为起点的滑行最远距离,由于我们至多只有四个方向滑行且要求只能朝低处滑行,那么我们的状态也最多从四个方向转移过来,于是我们使用搜索在递归的时候处理边界,然后回溯的时候不断地更新f[i][j]f[i][j]f[i][j]地值,详情请看代码代码#include<bits/stdc++.h>using nam原创 2022-02-26 22:25:14 · 310 阅读 · 0 评论 -
AcWing 285. 没有上司的舞会(树形DP)
题面链接https://www.acwing.com/problem/content/description/287/思路对于每一个员工都不希望自己和直接上司参加宴会,那么我们对于当前这个节点就有两种选法选和不选,于是我们定义f[p][0]f[p][0]f[p][0]表示不选p这个点的且以当前点为根的子树选法最大值,f[p][1]f[p][1]f[p][1]表示选p这个点的且以当前点为根的子树选法最大值,假设ppp的子节点集合为VVV那么显然f[p][0]=∑max(f[Vi][0],f[Vi][1]原创 2022-02-26 21:49:04 · 582 阅读 · 0 评论 -
AcWing 91. 最短Hamilton路径(状态压缩DP+哈密顿回路)
题目链接https://www.acwing.com/problem/content/description/93/思路这道题看似像一个最短路,但是并不是,因为我们要求对于每一个点都经过,但是最短路不能保证,所以我们换一个思路用DP,我们定义f[i][j]f[i][j]f[i][j]表示从0走到j,走过的所有点是i状态的最短路径,其中的i我们将其看为二进制表示,对于每一位我们用1表示这一个点走过,用0表示这一个点没走过,那么我们要经过第一个点是0,所以我们初始化f[1][0]=0f[1][0] = 0原创 2022-02-26 17:53:50 · 1089 阅读 · 1 评论 -
AcWing 291. 蒙德里安的梦想(状态压缩DP)
题目链接https://www.acwing.com/problem/content/293/思路我们用一个n位二进制表示一列的情况,那么一列的情况有2n2^n2n种,我们枚举塞1×21\times 21×2的方块数量,那么最后塞入2×12 \times 12×1的方块的数量也是固定了的,我们定义f[i][j]f[i][j]f[i][j]表示已经将前i−1i-1i−1列摆好,且从第i−1i−1i−1列,伸出到第iii列的状态是jjj的所有方案,我们枚举当前第iii列的情况时,我们应该是从i−1i-1i原创 2022-02-24 21:59:52 · 227 阅读 · 0 评论 -
AcWing 338. 计数问题(数位DP)
题目链接https://www.acwing.com/problem/content/340/思路我们想要快速求得[1,n][1,n][1,n]内所有数的某些数字出现的次数,那么我们要从十进制数位出发,我们从左往右或者从右往左枚举每一个数位,对于当前的这个数位我们是已经定了的,所以我们就看当前这个位置的前面和后面分别有多少种枚举的方法,首先无论当前的这一位是否大于我们要计算的位值,我们都会有(l−1)×p(l-1) \times p(l−1)×p的方案数量,如果当前计算的位值不为0的话那么说明还有前缀原创 2022-02-24 15:23:30 · 577 阅读 · 0 评论 -
编辑距离(线性DP+暴力匹配)
题目链接https://www.acwing.com/problem/content/901/思路其实这一道题的思路和上一道题是一样的,只不过我们对于每一次询问需要做n次匹配判断,如果当前的操作次数低于k那么说明我们这个字符串是合法的,关于怎么匹配俩字符串的最低花费次数,我们可以上一篇:最小编辑距离代码#include<bits/stdc++.h>using namespace std;const int N = 1e3+10;int n,m;char a[N][15],b原创 2022-02-21 14:55:21 · 169 阅读 · 0 评论 -
石子合并简化版(区间DP)
题目链接https://www.acwing.com/problem/content/284/思路因为只能合并相邻的两堆石子,并且首位不构成环,那么我们用f[i][j]f[i][j]f[i][j]表示区间[i,j][i,j][i,j]这个范围的一个合并最小值那么我们思考这个状态怎么转移过来,显然的是肯定是从更加细微的区间转移过来,那么我们就对区间进行一个划分操作,我们将其划分为[i,k][i,k][i,k]和[k+1,j][k+1,j][k+1,j]两部分,然后将这两个区间合并,那么我们只需要枚举一下原创 2022-02-21 17:11:44 · 364 阅读 · 0 评论 -
AcWing 900. 整数划分(完全背包计数问题)
题目链接https://www.acwing.com/problem/content/description/902/思路对于从[1,n][1,n][1,n]的每一个数我们能做的操作是选或者不选,并且我们在选的过程要从小到大,并且对于每一种数字我们可以选择无穷多个(但是在背包容量范围内,这里的话就是在n范围内),那么这就是一个完全背包计数问题的裸题了,因为状态只有选择或者不选那么不难发现状态转移方程为:f[i][j]=f[i−1][j]+f[i−1][j−k]f[i][j]=f[i-1][j] + f原创 2022-02-21 17:44:33 · 270 阅读 · 0 评论 -
AcWing 902. 最短编辑距离(线性DP)
题目链接https://www.acwing.com/problem/content/description/904/思路因为题目中有三种操作A字符串的方法:删除A中一个元素给A增加任意元素将A中任意位置替换成某个元素我们定义f[i][j]f[i][j]f[i][j]表示的是字符串A从[1,i][1,i][1,i]和字符串B[1,j][1,j][1,j]完成匹配需要的最少操作次数,那么我们考虑最A字符串的最后一个位置的操作情况如果A最后一个位置是删除操作,说明从A字符串中[1,i−1]原创 2022-02-21 11:09:01 · 250 阅读 · 0 评论 -
AcWing 897. 最长公共子序列(LCS朴素版)
题目连接https://www.acwing.com/problem/content/899/思路我们定义f[i][j]f[i][j]f[i][j]表示的是a串中长度为i和b串长度为j的最长公共子序列长度,那么我们当前匹配到的a[i]和b[j]如果相等f[i][j]f[i][j]f[i][j]的值一定是从f[i−1][j−1]f[i-1][j-1]f[i−1][j−1]转移过来的,即f[i][j]=f[i−1][j−1]+1f[i][j]=f[i-1][j-1]+1f[i][j]=f[i−1][j−1原创 2022-02-18 13:29:12 · 275 阅读 · 0 评论 -
AcWing 896. 最长上升子序列 II(二分优化LIS)
题目连接https://www.acwing.com/problem/content/description/898/思路我们用一个f[i]f[i]f[i]表示以长度为i结尾的子序列的最小值的大小,那么不难发现我们这个f数组是一个单调递增的序列,那么我们就能对我们往前匹配的过程做一个二分优化,也就是找到长度尽量大的且比当前a[i]a[i]a[i]值小的一个位置,如果我们发现当前的这个a[i]a[i]a[i]是比之前所有的元素都要大的,那么我们就应该让我们的最长序列的长度增加,并将a[i]a[i]a[i原创 2022-02-18 12:36:53 · 294 阅读 · 2 评论 -
AcWing 895. 最长上升子序列(LIS朴素做法)
题目连接https://www.acwing.com/problem/content/897/思路因为数据范围很小,所以我们定义f[i]f[i]f[i]表示的是以第i个元素结尾的最长上升子序列的长度,那么我们每次从[0,i]扫一遍然后去一个max就好啦代码#include<bits/stdc++.h>using namespace std;const int N = 5e2+10;int a[N][N],f[N][N];int n;int main(){ cin原创 2022-02-17 23:07:20 · 158 阅读 · 0 评论 -
AcWing 898. 数字三角形(线性DP)
题目连接https://www.acwing.com/problem/content/description/900/思路我们知道对于当前的这一层,只能从左上和正上方转移过来,那么我们定义f[i][j]f[i][j]f[i][j]表示的是从第一层到第i层第j列的最大路径数值和,那么不难发现f[i][j]=a[i][j]+max(f[i−1][j−1],f[i−1][j])f[i][j] = a[i][j] + max(f[i-1][j-1],f[i-1][j])f[i][j]=a[i][j]+max(原创 2022-02-17 23:06:29 · 267 阅读 · 0 评论 -
AcWing 9. 分组背包问题(分组背包模板)
题目连接https://www.acwing.com/problem/content/description/9/思路对于一个组里面的物品只能选一个我们可以通过集合划分的方式来看待这个问题,f[i][j]f[i][j]f[i][j]表示的是从前i个组中每个组选择一个物品其总容量不超过j的最大价值,那么我们就能用一个三层循环解决这个问题f[i][j]=max(f[i][j],f[i][j−v[i][k]]+w[i][k])f[i][j]=max(f[i][j],f[i][j-v[i][k]] + w[i原创 2022-02-17 19:10:41 · 532 阅读 · 0 评论 -
AcWing 5. 多重背包问题 II(二进制优化)
题目链接https://www.acwing.com/problem/content/5/思路part1受了完全背包和01背包的启发我们不难想到,一种高效的方法来优化,我们讲物品的次数做一个二进制拆分(不足的就用余数来补齐),那么对于这个拆分出来的这些次数我们就将其转化为一件“大”物品,那么我们单独堆这个拆分出来的值进行一个01背包,那么我们就能组合出[0,s[i]][0,s[i]][0,s[i]]范围内所有的情况,选或者不选嘛,那么我们对所有的物品都这样拆分,最终再跑一个01背包就好啦part2原创 2022-02-17 19:10:01 · 309 阅读 · 0 评论 -
AcWing 4. 多重背包问题(多重背包 朴素版)
题目链接https://www.acwing.com/problem/content/4/思路对于每一个物品我们在选择的时候是有限制的,所以我们进行选择的时候需要枚举一下可以选择的情况,注意的是我们在循环枚举物品的次数以及当前的背包容量的时候,背包容量一定要在物品的次数的上面,这样进行递推才是背包容量为j的最大价值,否则我们枚举的就是n次不同的背包,每次枚举一种物品的不同次数的价值,所以需要注意这一点代码#include<bits/stdc++.h>using namespace s原创 2022-02-17 19:09:18 · 302 阅读 · 0 评论 -
AcWing 3. 完全背包问题(完全背包模板)
题目链接https://www.acwing.com/problem/content/3/思路对于每一个物品我们可以选择无数次,那么我们可以直接枚举到V这个范围去,但是没必要,我们发现滚动优化后从前往后本身就是一个选择无限次的一个操作代码#include<bits/stdc++.h>using namespace std;const int N = 1e3+10;int f[N],v[N],w[N];int n,V;int main(){ cin>>原创 2022-02-17 19:08:37 · 265 阅读 · 0 评论 -
AcWing 2. 01背包问题(01背包模板)
题目链接https://www.acwing.com/problem/content/880/思路对于每一个物品我们能做一个选择,选上它(前提是当前的剩余背包容量够),或者不选,那么我们只需要在这其中取一个max即可,我们定义一个f[i][j]f[i][j]f[i][j]表示的含义是从前i个物品中选择背包容量最多为j的价值,那么我们只需要考虑当前第i个物品的取舍,也就是f[i][j]=max(f[i−1][j],f[i−1][j−v[i]]+w[i])f[i][j] = max(f[i-1][j],f原创 2022-02-17 19:08:00 · 220 阅读 · 0 评论