导弹拦截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;
}
//本题将经典的动态规划的模板融入进题干里,关键是要把它挖掘出来,就成功了!