一.概念

具有线性阶段划分的动态规划算法叫作线性动态规划(简称线性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的更多相关文章

  1. 动态规划篇——线性DP

    动态规划篇--线性DP 本次我们介绍动态规划篇的线性DP,我们会从下面几个角度来介绍: 数字三角形 最长上升子序列I 最长上升子序列II 最长公共子序列 最短编辑距离 数字三角形 我们首先介绍一下题目 ...

  2. 动态规划_线性dp

    https://www.cnblogs.com/31415926535x/p/10415694.html 线性dp是很基础的一种动态规划,,经典题和他的变种有很多,比如两个串的LCS,LIS,最大子序 ...

  3. 【线性DP】数字三角形

    题目链接 原题链接 题目描述 给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大. 7 3 ...

  4. 动态规划——线性dp

    我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...

  5. CH5102 Mobile Service【线性dp】

    5102 Mobile Service 0x50「动态规划」例题 描述 一个公司有三个移动服务员,最初分别在位置1,2,3处.如果某个位置(用一个整数表示)有一个请求,那么公司必须指派某名员工赶到那个 ...

  6. 洛谷P1140 相似基因(线性DP)

    题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了444种核苷酸,简记作A,C,G,TA,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. 在一个人类 ...

  7. 『最长等差数列 线性DP』

    最长等差数列(51nod 1055) Description N个不同的正整数,找出由这些数组成的最长的等差数列. 例如:1 3 5 6 8 9 10 12 13 14 等差子数列包括(仅包括两项的不 ...

  8. 线性DP总结(LIS,LCS,LCIS,最长子段和)

    做了一段时间的线性dp的题目是时候做一个总结 线性动态规划无非就是在一个数组上搞嘛, 首先看一个最简单的问题: 一,最长字段和 下面为状态转移方程 for(int i=2;i<=n;i++) { ...

  9. POJ-2346 Lucky tickets(线性DP)

    Lucky tickets Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3298 Accepted: 2174 Descrip ...

  10. 2018.08.16 洛谷P2029 跳舞(线性dp)

    传送门 简单的线性dp" role="presentation" style="position: relative;">dpdp. 直接推一推 ...

随机推荐

  1. 如何设计一个高性能的图 Schema

    本文整理自青藤云安全工程师--文洲在青藤云技术团队内部分享,分享视频参考:https://www.bilibili.com/video/BV1r64y1R72i 图数据库的性能和 schema 的设计 ...

  2. vue3页面使用vue2语法

    vue3页面: import { getCurrentInstance } from 'vue'; const { proxy } = getCurrentInstance(); proxy...

  3. Java 手动抛异常

    1 package com.bytezero.throwable; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 impor ...

  4. PaddleOCR 服务化部署(基于PaddleHub Serving)

    最近用到百度飞桨的 PaddleOCR,研究了一下PaddleOCR的服务化部署,简单记录一些部署过程和碰到的问题. 基础环境 paddlepaddle 2.5.2 python 3.7 paddle ...

  5. 我为什么使用Linux做开发

    系统选择 目前市面上主流的桌面操作系统在大多数人眼里只有Windows和MacOS,那为什么我没选择它们两呢? 首先,不选MacOS的原因,就是太贵.当然这是我的原因不是苹果的原因,我最早使用Linu ...

  6. coding 的pages 静态要六分钱一个月,我也是醉了。

    前言 前几天,收到个短信,说coding 竟然免费开放 动态pages,我这心说 NB啊,这咱得蹭上一波热度. github 总是打不开 gitee 每次pages都要手动点下发布,而且是静态的. c ...

  7. Vite-vue3 架构设计

    Vite-vue3 架构设计 基础信息 Gitee项目地址:https://gitee.com/pengchenggang/vite-vue3 1 创建vite-vue3 初始化脚本 $ npm in ...

  8. 常用Linux系统性能分析命令

    Linux系统提供了许多命令来分析系统性能.以下是一些常用的Linux系统性能分析命令: top:实时监视系统的运行状态和进程信息,包括CPU使用率.内存使用情况.进程状态等. 实例:直接在终端中输入 ...

  9. Python Numpy 中的打印设置函数set_printoptions

    一 概述 np.set_printoptions()用于控制Python中小数的显示精度. 二 解析 np.set_printoptions(precision=None, threshold=Non ...

  10. ijkplayer编译-RTSP

    1.编译平台和版本 使用操作系统 Ubuntu 18.04 使用ndk版本:android-ndk-r14b-linux-x86_64.zip (使用r17c编译会报错) AS版本:4.2.2 1.1 ...