导弹拦截(动态规划 C++)

导弹拦截DP
总时间限制: 1500ms 内存限制: 65536kB
描述
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算最少需要多少套系统才能拦截所有导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
输入
输入有两行,第一行,输入雷达捕捉到的敌国导弹的数量k(k<=10000),第二行,输入k个整数,表示k枚导弹的高度(高度可以为负,导弹可以在海里拦截),按来袭导弹的袭击时间顺序给出,以空格分隔。
输出
只有一行,包含两个整数,用空格分开
第1个数表示一套系统最多打多少导弹;
第2个数表示最少需要多少套系统才能拦截所有导弹。
样例输入

4
9 6 7 8

样例输出

2 3

提示
最长上升(下降)子序列

思路点拔:有些OI选手一看到题,就开始使用贪心,其实也能做,而且是正解,但题目上写了DP,所以我们不妨用动态规划来做一做这个题,首先,每套拦截系统打出的导弹的高度都不能高于前一发,所以,当我们发现后一发导弹的高度高于前一发时
我们就需要多用一套拦截系统,所以,求需要多少套拦截系统,就是求最长上升子序列,二一套导弹最多能拦截多少枚导弹,也就是找出最长下降子序列,所以,本题就转化成了经典的动态规划了,但是需要注意:本题的时间限制为1.5秒,如果分别求出最长上升子序列再求最长下降子序列时,就会超时,所以我们要把它们压缩到一个循环里面完成,光说不行,上代码才是王道!!

#include<cstdio>
#include<iostream>
using namespace std;
int v[10005],f[10005],g[10005]={0,1},maxn,minn; 
//maxn表示最长上升子序列长度,minn表示最长下降子序列的长度
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]); //输入每枚导弹的高度
        f[i]=g[i]=1; 
        for(int j=1;j<i;j++)
        {
            if(v[i]<=v[j]) //求最长上升子序列
            {
                f[i]=max(f[i],f[j]+1);
            }
            if(v[i]>v[j]) //求最长下降子序列
            {
                g[i]=max(g[i],g[j]+1);
            }
        }
        if(f[i]>maxn) //求出最长上升子序列的长度
        {
            maxn=f[i];
        }
        if(g[i]>minn) //求出最长下降子序列的长度
        {
            minn=g[i];
        }
    }
    printf("%d %d\n",maxn,minn); 
    /*输出最长上升子序列长度与最长下降子序列的长度,也就是需要多少套拦截
    系统与一套系统最多拦截多少枚导弹*/
    return 0;
}
//本题将经典的动态规划的模板融入进题干里,关键是要把它挖掘出来,就成功了!

猜你喜欢

转载自blog.csdn.net/qq_42995099/article/details/82054951