记忆化搜索

将之后可以重复用到的子问题的答案进行记录。典例:斐波那契数列、走楼梯、走蜂窝。

斐波那契改进:走楼梯,第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、确定状态转移方程

  1. 参数够不够(记录历史状态)
  2. 分情况(最后一次操作方式,取不取,怎样取)
  3. 注意边界是什么
  4. 无后效性(如:求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相关推荐

  1. 0x51.动态规划 - 线性DP(习题详解 × 10)

    目录 0x51.动态规划 - 线性DP 0x51.1 LIS问题 Problem A. 登山 (最长下降子序列) Problem B. 友好城市(思维) Problem C. 最大上升子序列和 0x5 ...

  2. 动态规划 —— 线性 DP

    [概述] 线性动态规划,是较常见的一类动态规划问题,其是在线性结构上进行状态转移,这类问题不像背包问题.区间DP等有固定的模板. 线性动态规划的目标函数为特定变量的线性函数,约束是这些变量的线性不等式 ...

  3. dp2:线性dp、区间dp、计数dp.

    线性dp   动态规划时间复杂度分析,状态数目与状态转移次数相乘. 数字三角形 数字三角形 以集合的观点考虑dp问题. #include<iostream> #include<cst ...

  4. 动态规划 —— 线性 DP —— 字符串编辑距离

    [概述] 字符串编辑距离,即 Levenshtein 距离,是俄国科学家 Vladimir Levenshtein 提出的概念,是指从一个字符串修改到另一个字符串时,编辑单个字符所需的最少次数,编辑单 ...

  5. 算法5:线性DP与区间DP

    目录 一.算法解释 二.经典例题:数字三角形 三.最长上升子序列 四.最长公共子序列 五 .最短编辑距离 六.编辑距离(和上题十分相似) 七 .区间DP(状态表示是一个区间) 一.算法解释 适用范围: ...

  6. 动态规划 —— 线性 DP —— 最大和问题

    [最大子序列和] 问题定义:对于给定序列 a1,a2,a3--an 寻找它的连续的最大和子数组. 用数组 dp[i] 来保存当前最大的连续子数组,循环遍历每个数,然后每次检验 dp[i-1] 是否大于 ...

  7. 动态规划 —— 线性 DP —— 序列问题

    [基本概念] 子序列: 一个序列 A=a1,a2,--an 中任意删除若干项,剩余的序列叫做 A 的一个子序列.也可以认为是从序列 A 按原顺序保留任意若干项得到的序列.(例如:对序列{1,3,5,4 ...

  8. Sticks UVA - 307(切木棍 线性区间dp,线性dp,区间思想。)

    题目大意:将n节木棒接成m个长度相等的木条,要求木条的长度尽可能的短 Time limit     3000 ms OS     Linux George took sticks of the sam ...

  9. AcWing 1018. 最低通行费【动态规划】【线性DP】【数字三角形】

    AcWing 1018. 最低通行费 一.题目链接 二.题目分析 (一)算法标签 (二)解题思路 三.AC代码 四.其它题解 一.题目链接 AcWing 1018. 最低通行费 二.题目分析 (一)算 ...

  10. 动态规划:线性dp、背包问题、区间3

    区间DP 2955 -- Brackets 给定一个由字符 a1a2 ... an 组成的括号序列,你的目标是找到最长的正则括号序列的长度,它是 s 的子序列.也就是说,您希望找到最大的 m,使得对于 ...

最新文章

  1. WeeklyBlogging_20100722
  2. java.lang.ExceptionInInitializerError的原因
  3. 哈尔滨理工C语言程序设计精髓_计算机科学与信息工程学院C语言程序设计竞赛圆满完成!...
  4. 紧急预警:wls9_async_response.war组件漏洞的延续
  5. tcpdump 命令祥解
  6. python循环输入字符串_Python基础-条件判断、循环、字符串格式化
  7. axios_的其他方式发送请求_使用axios.request .get .delete .post .put 等方法发送请求---axios工作笔记005
  8. bzoj2539: [Ctsc2000]丘比特的烦恼
  9. csdn泄漏密码分析
  10. 百度旗下网站暗藏恶意代码——劫持用户电脑疯狂“收割”流量
  11. opencv的下载报错解决
  12. Redis数据丢失问题
  13. 网易微专业python全栈工程师_Python学习笔记:6.3.10 flash WTF数据验证,6310flaskwtf
  14. 在godot的canvas_item着色器中构建逆投影矩阵和逆视图矩阵
  15. Linux4步快速搭建DNS服务器
  16. 使用跳板机在Pycharm上配置内网服务器
  17. 针对Windows10下EPLAN2.7频繁重启的解决办法
  18. if(男深圳集体户口女非深圳户口)深圳准生证办理材料及流程
  19. 阿里云服务器的购买以及使用
  20. java 注解处理器的作用_Java注解处理器

热门文章

  1. 8位数控分频器的设计_数控分频器的设计
  2. [ERP管理]实施ERP项目需提防能人插手
  3. adb unauthorized 解决方案
  4. 第七届蓝桥杯(软件类)C++决赛A组题解
  5. 解决:Could not build wheels for pycocotools, which is required to install pyproject.toml-based
  6. 双非的我18年哈工大建筑考研的那些事
  7. jQuery动画效果之-fadeTo
  8. 关于计算机发展经历了四个时代,划分的依据以及应用领域.
  9. C# ComboBox SelectedText属性和SelectedValue属性理解
  10. 华为三层交换机VRRP与DHCP综合实验