动态规划(三)——线性dp
一.概念
具有线性阶段划分的动态规划算法叫作线性动态规划(简称线性DP)。若状态包含多个维度,则每个维度都是线性划分的阶段,也属于线性DP,如下图所示:

二.线性dp的三大经典例题
1.LIS问题:求最长上升子序列
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数N。
第二行包含N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000,
−10&9≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
思路:
确定函数为f[i]表示以第i个数结尾的所有子序列集合,f[i]=最大子序列长度;确定状态转移方程:枚举第i个数前面的数j,如果a[j] < a[i]说明a[j]可能是以a[i]为结尾的最长子序列的倒数第二个数,如果是就用f[j]+1更新f[i]。所以状态转移方程为f[i] = max(f[i], f[j]+1)
时间复杂度O(n2)
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=10010;
int n,a[N],f[N];
int main(){
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++){
f[i]=1;
for(int j=0;j<i;j++)
if(a[j]<a[i])
f[i]=max(f[i],f[j]+1);
}
int res=0;
for(int i=0;i<n;i++) res=max(res,f[i]);
cout<<res<<endl;
return 0;
}
2.LCS问题:数字三角形

代码:
#include <bits/stdc++.h>
using namespace std;
const int N=510;
const int inf=0x3f3f3f3f;
int n,m;
//f[i][j]表示到达第i行j列这个位置的最大值
int a[N][N],f[N][N];
int main(){
scanf("%d",&n);
//读入三角形数据
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
scanf("%d",&a[i][j]);
//初始化f
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
f[i][j] = -inf;
//线性dp
f[0][0] = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
f[i][j] = max(f[i-1][j-1], f[i-1][j]) + a[i][j];
int ans = -inf;
for(int i=1; i<=n; i++)
ans = max(ans, f[n][i]);
printf("%d", ans);
return 0;
}
3.LCS问题:最长公共子序列
信息学小组截获了两个序列,序列A和B,规定两个序列所隐藏的信息就是两者的最长公共子串
(注意,这里的子串是指连续的,比如说212325233中212是212325233的子串,而213或者223都不是212325233的子串),
现在,他们将这个任务交给你,你要找出这两个序列所隐藏信息的长度
输入格式
两行,A和B(A、B长度均不大于1000,A、B均由0~9之间的数字组成)
输出格式
一个整数为最长公共子串的长度
样例
样例输入
212325233
312123223
样例输出
5
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
char s1[N], s2[N];
int dp[N][N];
int main(){
cin>>s1+1>>s2+1;// 从1开始存储字符串,方便后续的状态转移
int len1=strlen(s1+1);
int len2=strlen(s2+1);
int ans=0;
for(int i=1;i<=len1;i++)
for(int j=1;j<=len2;j++)
if(s1[i]==s2[j]){
dp[i][j]=dp[i-1][j-1]+1;//当前字符相等,最长公共子串长度加1
ans=max(ans,dp[i][j]);
}
else dp[i][j]=0;//当前字符不相等,最长公共子串长度为0
cout<<ans;
return 0;
}
三.典例之拦截导弹
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:
虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),
计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
输入只有一行,为若干个正整数,一次为导弹的高度。
输出格式
第一行为最多能拦截的导弹数;
第二行为要拦截所有导弹最少要配备的系统数
样例
样例输入
389 207 155 300 299 170 158 65
样例输出
6
2
核心思想:第一个答案是最长不下降子序列,比较基础,第二个答案是最长上升子序列

y总讲的非常明白哈,这个是基于贪心的思想,贪心得出一堆子序列,最优解也有一堆子序列
只要证明贪心得出的子序列个数与最优解表示的子序列个数一样就行了,证明方式就是A >= B , A <= B,就可以得出 A == B , 显然A >= B , 因为最优解的子序列数量一定是最少的,现在只需要证明A <= B,首先,两个如果不一样的话必定会有不一样的子序列,这对子序列必定会有第一个不相等的数,贪心的策略就是把他接在现有的子序列结尾最小值的后面,所以现在最优解的这个位置的数一定比他大,所以就可以替换掉,所以子序列的个数是不变的,所以又证明了A >= B,所以A == B,现在怎么用代码实现这个贪心的策略,就只需要维护各个子序列的结尾就行了,对于每一个数无非就两种操作,一种是排在某个序列之后,一种是另外再开辟一个序列,而且由于贪心策略的第二条维护的各个子序列的结尾是单调上升的,用这个序列能将所有导弹全部拦截下来,求最小值的话那么就是求最短上升子序列的个数了
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int f1[N],f[N],a[N];
int main(){
int n=1,res1=0;
while(scanf("%d",&a[n])!=EOF) n++;
for(int i=1;i<n;i++){
f1[i]=1;
for(int j=1;j<i;j++){
if(a[i]<=a[j]) f1[i]=max(f1[i],f1[j]+1);
}
res1=max(res1,f1[i]);
}
int res2=0;
for(int i=1;i<n;i++){
f1[i]=1;
for(int j=1;j<i;j++){
if(a[i]>a[j]) f1[i]=max(f1[i],f1[j]+1);
}
res2= max(res2,f1[i]);
}
cout<<res1<<"\n"<<res2<<endl;
return 0;
}
如有错误,欢迎大佬们在评论区指正小蒟蒻博主的错误~
#一名爱打篮球的oier#
动态规划(三)——线性dp的更多相关文章
- 动态规划篇——线性DP
动态规划篇--线性DP 本次我们介绍动态规划篇的线性DP,我们会从下面几个角度来介绍: 数字三角形 最长上升子序列I 最长上升子序列II 最长公共子序列 最短编辑距离 数字三角形 我们首先介绍一下题目 ...
- 动态规划_线性dp
https://www.cnblogs.com/31415926535x/p/10415694.html 线性dp是很基础的一种动态规划,,经典题和他的变种有很多,比如两个串的LCS,LIS,最大子序 ...
- 【线性DP】数字三角形
题目链接 原题链接 题目描述 给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大. 7 3 ...
- 动态规划——线性dp
我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...
- CH5102 Mobile Service【线性dp】
5102 Mobile Service 0x50「动态规划」例题 描述 一个公司有三个移动服务员,最初分别在位置1,2,3处.如果某个位置(用一个整数表示)有一个请求,那么公司必须指派某名员工赶到那个 ...
- 洛谷P1140 相似基因(线性DP)
题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了444种核苷酸,简记作A,C,G,TA,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. 在一个人类 ...
- 『最长等差数列 线性DP』
最长等差数列(51nod 1055) Description N个不同的正整数,找出由这些数组成的最长的等差数列. 例如:1 3 5 6 8 9 10 12 13 14 等差子数列包括(仅包括两项的不 ...
- 线性DP总结(LIS,LCS,LCIS,最长子段和)
做了一段时间的线性dp的题目是时候做一个总结 线性动态规划无非就是在一个数组上搞嘛, 首先看一个最简单的问题: 一,最长字段和 下面为状态转移方程 for(int i=2;i<=n;i++) { ...
- POJ-2346 Lucky tickets(线性DP)
Lucky tickets Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3298 Accepted: 2174 Descrip ...
- 2018.08.16 洛谷P2029 跳舞(线性dp)
传送门 简单的线性dp" role="presentation" style="position: relative;">dpdp. 直接推一推 ...
随机推荐
- kafka的数据同步原理ISR、ACK、LEO、HW
1.数据可靠性保证,数据同步 为保证 producer 发送的数据,能可靠的发送到指定的 topic,topic 的每个 partition 收到 producer 发送的数据后,都需要向 produ ...
- 9、zookeeper的核心ZAB协议
ZAB协议 zab协议的全称是 Zookeeper Atomic Broadcast (zookeeper原子广播).zookeeper是通过zab协议来保证分布式事务的最终一致性 1.ZAB协议是专 ...
- iview 动态表单验证 FormItem prop rules v-show 动态表单校验
iview 动态表单验证 FormItem prop rules v-show 重点1 用v-show 控制显示隐藏 重点2 prop 指定字段 重点3 :rules 动态指定规则 <div v ...
- tapable - webpack 的 hooks - getAc - 异步流程控制
tapable - webpack 的 hooks,类似自己的 getAc 官方地址 https://www.npmjs.com/package/tapable 随便找了篇文章:聊聊 Webpack ...
- 关于vscode的复制粘贴的问题
有的是因为安装了vim的插件,卸掉即可.或者直接在快捷键设置里面直接改变复制粘贴的快捷键!
- day06-Java流程控制
Java流程控制 1.用户交互Scanner java.util.Scanner是Java5的新特征,我们可以通过Scannner类来获取用户的输入. 基本语法: Scanner s = new Sc ...
- php处理序列化jQuery serializeArray数据
介绍jquery的几个常用处理表单的函数: 1.序列化表单内容元素为字符串,常用于ajax提交. $("form").serialize() 2. serializeArray() ...
- 【atcoder abc281_d】动态规划
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * @ ...
- 使用Servlet实现文件下载
一位朋友最近在学习JavaWeb开发,开始学习文件下载操作,他自己尝试着去网上看一些教程,总的来说也不是太了解,就让我和他说说,如何实现文件下载功能.我和他说了一下大致的思路,主要分为前端和后端两部分 ...
- python高级技术(网络编程一)
一 socket是什么 链接socket前要熟悉计算机网络基础请看链接:https://www.cnblogs.com/coderxueshan/p/17344739.html Socket是应用层 ...