动态规划:线性dp、背包问题、区间1
记忆化搜索
将之后可以重复用到的子问题的答案进行记录。典例:斐波那契数列、走楼梯、走蜂窝。
斐波那契改进:走楼梯,第i阶台阶不能走。直接强行让第i级台阶方案数等于0即可。
推广:从起点到终点的最短路径方案数,可以通过广搜标记计算每一个点到达的方案数。
1163 -- The Triangle
图 1 显示了一个数字三角形。编写一个程序,计算从顶部开始到底部某处结束的路线上通过的最大数字总和。每一步都可以对角线向左或向右对角线向下。
从上往下写比较容易想,但从下往上写可以直接在顶点取到答案,数组开的也小,只用存输入数据即可,后面会自动更新。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f, maxn=105;
int n,f[maxn][maxn];
int main(){cin>>n;for(int i=1;i<=n;++i){for(int j=1;j<=i;++j)scanf("%d",&f[i][j]);}for(int i=n-1;i>=1;--i){for(int j=1;j<=i;++j)f[i][j]+=max(f[i+1][j],f[i+1][j+1]);}cout<<f[1][1];return 0;
}
动态规划
分类加法原理:通过迭代相加得到答案
分步乘法原理:通过迭代相乘得到答案
多阶段决策过程最优化问题,一般阶段与阶段决策过程有相关性,通过记录每个阶段的最优决策结果来达到全局最优。
动态规划使用的基本条件:具有相同的子问题,满足最优子结构。比如说下列选择模4最小的路径的模数。只有找到最优子结构,才可以用动态规划。
既然所有之前经历过的余数将会对后方产生结果,那不如直接设f[i][0,1,2,3],假设到达i点时需要其余数等于x,从前一个点到达i的路长为y,则之前的余数应当等于x-y。体现了动态规划的记录对未来有影响的数据的特点,即:
过去的状态只能通过现在的状态影响未来(翻译:要是你觉着这个状态数据会对未来产生影响,那你就把它记录下来)。走楼梯再次加难度:如果走过第50阶台阶,那就不能走第100阶台阶。
由“记录历史”原则,我们可以设置数组f[i][0,1],其中f[i][0]表示没上过50,f[i][1]表示上过。
i<50: f[i][0]=f[i-1][0]+f[i-2][0], f[i][1]=0 //根本没上过50i=50: f[50][0]=0, f[50][1]=f[49][0]+f[48][0] //记录50的方案数50<i<100: f[i][0]=f[i-1][0]+f[i-2][0], f[i][1]=f[i-1][1]+f[i-2][1] //只要走过50级台阶,就从走过的方案中数i=100: f[i][0]=f[i-1][0]+f[i-2][0], f[i][1]=0 //上过50就别想上100i>100: f[i][0]=f[i-1][0]+f[i-2][0], f[i][1]=f[i-1][1]+f[i-2][1] //同 50<i<100
动态规划的一般步骤
做多了就不用了,只用于初学阶段。
1、结合原问题和子问题确定状态,基本是题目求什么我们就设什么,并做一些细微调整(如走楼梯)。
2、确定状态转移方程
- 参数够不够(记录历史状态)
- 分情况(最后一次操作方式,取不取,怎样取)
- 注意边界是什么
- 无后效性(如:求A就要求B,求B就要求C,求C就要求A,这种就不行)
3、考虑是否需要优化
4、编程实现:递归、记忆化搜索
例2 路径条数
N*M棋盘,过河卒需从左上角走到右下角,可以向下或向右,求路径条数。
左边界和上边界全部设为1,式子为f[i][j]=f[i-1][j]+f[i][j-1],递推即可。
又可以发现,这是个斜着的杨辉三角,即可以联系组合数求,等于。
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网[NOIP2002]过河卒
如图,A 点有一个过河卒,需要走到目标 B 点。卒行走规则:可以向下、或者向右。同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点。例如上图 C 点上的马可以控制 9 个点(图中的P1,P2 … P8 和 C)。卒不能通过对方马的控制点。
细节问题:要考虑到边界点只能从左向右或从上到下,所以一旦有马拦就全变为0。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f, maxn=105;
int n,m,x,y,jg[30][30];
ll f[maxn][maxn];
int dx[]={0,2,2,1,1,-2,-2,-1,-1};
int dy[]={0,1,-1,2,-2,1,-1,2,-2};
int main(){cin>>n>>m>>x>>y;for(int i=0;i<9;++i)if(x+dx[i]<0||y+dy[i]<0||x+dx[i]>n||y+dy[i]>m) continue;else jg[x+dx[i]][y+dy[i]]=1;for(int i=0;i<=n;++i) f[i][0]=f[0][i]=1;for(int i=0;i<=n;++i){for(int j=0;j<=m;++j)if(!jg[i][j]){if(i==0&&j==0) continue;else if(i==0) f[i][j]=f[i][j-1];else if(j==0) f[i][j]=f[i-1][j];else f[i][j]=f[i-1][j]+f[i][j-1];}else f[i][j]=0;//}cout<<f[n][m];return 0;
}
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网[NOIP2008]传球游戏
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球的方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。
实际上就是求第i次传球,球在第j个人手中的方案数。此题给我的感悟就是:要把数据转化成自己好理解的形式进行dp会好想一些;一般是从结果倒着推过程;数组就是为了存信息的,一维二维具体情况不重要。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f, maxn=35;
int n,m;
ll f[maxn][maxn];
int main(){cin>>n>>m;if(m==1){cout<<0;return 0;}f[0][1]=1;for(int i=1;i<=m;++i){for(int j=1;j<=n;++j){if(j==1) f[i][j]=f[i-1][j+1]+f[i-1][n];else if(j==n) f[i][j]=f[i-1][j-1]+f[i-1][1];else f[i][j]=f[i-1][j+1]+f[i-1][j-1];}}cout<<f[m][1];return 0;
}
最长不下降子序列
给出一组数,如果后面的数总大于前面的数,则称为最长不下降子序列。给出一组数,求最长不下降子序列(可以跳着选)。
我们并不知道当到第i个数的时候,是否该选i以及之前的长度能不能让我们去选i以成为当前最优解。所以我们考虑每次都必须选第i个数,并从第一个数开始找比它小的数,并将选择第i个数的最大长度等于之前小于i的数的最大的长度+1。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f, maxn=35;
int n,m, a[maxn],f[maxn];
int main(){cin>>n;for(int i=1;i<=n;++i){cin>>a[i];f[i]=1;}for(int i=2;i<=n;++i){int maxx=0;for(int j=1;j<i;++j){if(a[i]>a[j]) maxx=max(maxx,f[j]);}f[i]=maxx+1;}int maxx=-1;for(int i=1;i<=n;++i)maxx=max(maxx,f[i]);for(int i=1;i<=n;++i)cout<<f[i]<<' ';cout<<endl;cout<<maxx;return 0;
}
[SHOI2002]滑雪 - 洛谷
输入的第一行为表示区域的二维数组的行数 RR 和列数 CC。下面是 RR 行,每行有 CC 个数,代表高度(两个数字之间用 11 个空格间隔)。输出区域中最长滑坡的长度。
为啥能保证查到数组中存放值,就一定是最长的坡呢?因为我们的代码逻辑十分严密,没算出来的值直接就派给分身(递归)去算了鸭!
细节问题:别忘了每个点最小长度都为1鸭,要不就会少算一个长度QAQ
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f, maxn=105;
int r,c,mp[maxn][maxn],f[maxn][maxn],ans;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int calc(int x,int y){if(f[x][y]) return f[x][y];//因为代码逻辑严密,保证了只要是算出来的数,//就一定是x,y作为起点最长的滑雪道长度 f[x][y]=1;//别忘记设初始值QAQ for(int i=0;i<4;++i){int xx=x+dx[i], yy=y+dy[i];if(xx<1||xx>r||yy<1||yy>c||mp[xx][yy]>=mp[x][y])continue;calc(xx,yy);f[x][y]=max(f[x][y],f[xx][yy]+1);}return f[x][y];
}
int main(){cin>>r>>c;//行列 for(int i=1;i<=r;++i)for(int j=1;j<=c;++j)cin>>mp[i][j];//读入图 for(int i=1;i<=r;++i)for(int j=1;j<=c;++j)ans=max(ans,calc(i,j));cout<<ans;return 0;
}
最大子段和 - 洛谷
给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。
如果我们考虑a[i]为第i个数,f[i]表示第i个数一定要选的区间和,那么可以从一开始维护一个最大数的区间段,即f[i]=max(a[i], f[i-1] + a[i]) ,因为已经保证了之前选的区间一定是最大的且与i连续的,所以递推式子成立。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f, maxn=200005;
int n,a[maxn],f[maxn],ans=-inf;
int main(){cin>>n;for(int i=1;i<=n;++i)cin>>a[i];for(int i=1;i<=n;++i)f[i]=max(f[i-1]+a[i],a[i]);for(int i=1;i<=n;++i)ans=max(ans,f[i]);cout<<ans;return 0;
}
动态规划:线性dp、背包问题、区间1相关推荐
- 0x51.动态规划 - 线性DP(习题详解 × 10)
目录 0x51.动态规划 - 线性DP 0x51.1 LIS问题 Problem A. 登山 (最长下降子序列) Problem B. 友好城市(思维) Problem C. 最大上升子序列和 0x5 ...
- 动态规划 —— 线性 DP
[概述] 线性动态规划,是较常见的一类动态规划问题,其是在线性结构上进行状态转移,这类问题不像背包问题.区间DP等有固定的模板. 线性动态规划的目标函数为特定变量的线性函数,约束是这些变量的线性不等式 ...
- dp2:线性dp、区间dp、计数dp.
线性dp 动态规划时间复杂度分析,状态数目与状态转移次数相乘. 数字三角形 数字三角形 以集合的观点考虑dp问题. #include<iostream> #include<cst ...
- 动态规划 —— 线性 DP —— 字符串编辑距离
[概述] 字符串编辑距离,即 Levenshtein 距离,是俄国科学家 Vladimir Levenshtein 提出的概念,是指从一个字符串修改到另一个字符串时,编辑单个字符所需的最少次数,编辑单 ...
- 算法5:线性DP与区间DP
目录 一.算法解释 二.经典例题:数字三角形 三.最长上升子序列 四.最长公共子序列 五 .最短编辑距离 六.编辑距离(和上题十分相似) 七 .区间DP(状态表示是一个区间) 一.算法解释 适用范围: ...
- 动态规划 —— 线性 DP —— 最大和问题
[最大子序列和] 问题定义:对于给定序列 a1,a2,a3--an 寻找它的连续的最大和子数组. 用数组 dp[i] 来保存当前最大的连续子数组,循环遍历每个数,然后每次检验 dp[i-1] 是否大于 ...
- 动态规划 —— 线性 DP —— 序列问题
[基本概念] 子序列: 一个序列 A=a1,a2,--an 中任意删除若干项,剩余的序列叫做 A 的一个子序列.也可以认为是从序列 A 按原顺序保留任意若干项得到的序列.(例如:对序列{1,3,5,4 ...
- Sticks UVA - 307(切木棍 线性区间dp,线性dp,区间思想。)
题目大意:将n节木棒接成m个长度相等的木条,要求木条的长度尽可能的短 Time limit 3000 ms OS Linux George took sticks of the sam ...
- AcWing 1018. 最低通行费【动态规划】【线性DP】【数字三角形】
AcWing 1018. 最低通行费 一.题目链接 二.题目分析 (一)算法标签 (二)解题思路 三.AC代码 四.其它题解 一.题目链接 AcWing 1018. 最低通行费 二.题目分析 (一)算 ...
- 动态规划:线性dp、背包问题、区间3
区间DP 2955 -- Brackets 给定一个由字符 a1a2 ... an 组成的括号序列,你的目标是找到最长的正则括号序列的长度,它是 s 的子序列.也就是说,您希望找到最大的 m,使得对于 ...
最新文章
- WeeklyBlogging_20100722
- java.lang.ExceptionInInitializerError的原因
- 哈尔滨理工C语言程序设计精髓_计算机科学与信息工程学院C语言程序设计竞赛圆满完成!...
- 紧急预警:wls9_async_response.war组件漏洞的延续
- tcpdump 命令祥解
- python循环输入字符串_Python基础-条件判断、循环、字符串格式化
- axios_的其他方式发送请求_使用axios.request .get .delete .post .put 等方法发送请求---axios工作笔记005
- bzoj2539: [Ctsc2000]丘比特的烦恼
- csdn泄漏密码分析
- 百度旗下网站暗藏恶意代码——劫持用户电脑疯狂“收割”流量
- opencv的下载报错解决
- Redis数据丢失问题
- 网易微专业python全栈工程师_Python学习笔记:6.3.10 flash WTF数据验证,6310flaskwtf
- 在godot的canvas_item着色器中构建逆投影矩阵和逆视图矩阵
- Linux4步快速搭建DNS服务器
- 使用跳板机在Pycharm上配置内网服务器
- 针对Windows10下EPLAN2.7频繁重启的解决办法
- if(男深圳集体户口女非深圳户口)深圳准生证办理材料及流程
- 阿里云服务器的购买以及使用
- java 注解处理器的作用_Java注解处理器
热门文章
- 8位数控分频器的设计_数控分频器的设计
- [ERP管理]实施ERP项目需提防能人插手
- adb unauthorized 解决方案
- 第七届蓝桥杯(软件类)C++决赛A组题解
- 解决:Could not build wheels for pycocotools, which is required to install pyproject.toml-based
- 双非的我18年哈工大建筑考研的那些事
- jQuery动画效果之-fadeTo
- 关于计算机发展经历了四个时代,划分的依据以及应用领域.
- C# ComboBox SelectedText属性和SelectedValue属性理解
- 华为三层交换机VRRP与DHCP综合实验