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. 给出题解

全部评论

相关推荐

10-30 23:23
已编辑
中山大学 Web前端
去B座二楼砸水泥地:这无论是个人素质还是专业素质都👇拉满了吧
点赞 评论 收藏
分享
dongsheng66:如果想进大厂的话,在校经历没必要占这么大篇幅,可以把专业技能单独放一个专栏写,可以加个项目经历
点赞 评论 收藏
分享
服从性笔试吗,发这么多笔,现在还在发。
蟑螂恶霸zZ:傻 x 公司,发两次笔试,两次部门匹配挂,
投递金山WPS等公司10个岗位 >
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务