26 动态规划DP--最长递增子序列(LIS)
理论说明
最长递增子序列是动态规划中最经典的问题之一,我们讨论这个问题开始,循序渐进的了解动态规划的相关知识要点。
有序列{a1,a2,...,an},我们求其最长递增子序列长度。按照递推求解的思想,我们用F[i]代表若递增序列以ai结尾时他的最长长度。当i比较小时,我们容易求解其值,如F[1]=1.那么,如何由已经求得的F[i]值推得后面的值呢? 假设F[1]到F[x-1]的值都已经确定了,注意到,以ax结尾的递增子序列,除了长度1的情况,其他情况中,ax都紧跟在一个由ai(i<x)组成的递增子序列之后,要求以ax结尾的最长递增子序列的长度,我们依次比较ax与之前所有的ai(i<x)。若ai小于ax,说明ax可以跟在以ai结尾的递增子序列之后,形成一个新的递增子序列。又因为以ai为结尾的递增子序列最长长度已经获得,那么在这种情况下,由以ai结尾的最长递增子序列在加上ax得到的新的序列,其长度也是可以确定地,取这些长度的最大值,我们即可能够得到F[x]的值。特殊的,当没有ai(i<x)小于ax,那么以ax结尾的递增子序列最长长度为1。
综上所述: F[1]=1
F[i]=max{1,F[j]+1|ai>aj&&j<i};
题目来源
2007年北京大学计算机研究生机试真题
题目描述
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
输入说明
每组输入有两行, 第一行,输入雷达捕捉到的敌国导弹的数量k(k<=25), 第二行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。
输出说明
每组输出只有一行,包含一个整数,表示最多能拦截多少枚导弹。
样例展示
输入:
8
300 207 155 300 299 170 158 65
输出:
6
问题分析
由题意不难看出,要求最多能够拦截多少枚导弹,即在按照袭击顺序排列的导弹高度中求其最长不增序列。这就和上面分析的差不多了。直接把递推公式拿过来稍微改一下就可以啦:
综上所述: F[1]=1
F[i]=max{1,F[j]+1|ai<=aj&&j<i};
C++代码
#include<iostream>
using namespace std;
int h[30];
int dp[30];
int main() {
int n;
while(scanf("%d",&n)!=EOF) {
//输入
for(int i=1;i<=n;i++) {
scanf("%d",&h[i]);
}
//求解dp
for(int i=1;i<=n;i++) { //按照顺序求解dp[i]
int tmax=1;
for(int j=1;j<i;j++) { //遍历前面的
if(h[i]<=h[j]) {
tmax=max(tmax,dp[j]+1);
}
}
dp[i]=tmax;
}
//最大值
int ans=1;
for(int i=1;i<=n;i++) {
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
}
合唱队形
https://www.nowcoder.com/questionTerminal/cf209ca9ac994015b8caf5bf2cae5c98
C++代码
#include<iostream>
using namespace std;
int h[200];
int dp1[200];
int dp2[200];
int main() {
int n;
while(scanf("%d",&n)!=EOF) {
//读入
for(int i=1;i<=n;i++) {
scanf("%d",&h[i]);
}
//求解dp1[i]
for(int i=1;i<=n;i++) {
dp1[i]=1;
for(int j=1;j<i;j++) {
if(h[i]>h[j]) {
dp1[i]=max(dp1[i],dp1[j]+1);
}
}
}
//求解dp2
for(int i=n;i>=1;i--) {
dp2[i]=1;
for(int j=n;j>i;j--) {
if(h[i]>h[j]) {
dp2[i]=max(dp2[i],dp2[j]+1);
}
}
}
int maxt=1;
for(int i=1;i<=n;i++) {
maxt=max(maxt,dp1[i]+dp2[i]-1);
}
printf("%d\n",n-maxt);
}
return 0;
}
Leetcode题目太多,不知道如何准备高校夏令营?欢迎关注本专栏,和本小白一起准备夏令营吧! 本专题的规划如下: 截止到4月下旬:以王道考研为依托,提供夏令营机考的准备计划,打好基础 截止到5月中旬:以剑指offer进一步加强 本专题的内容如下: 1. 给出题目的在线测试链接,方面您检查代码的正确性 2. 给出题解