拦截导弹 (OpenJ_Bailian - 2945 )
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
Input
输入有两行,
第一行,输入雷达捕捉到的敌国导弹的数量k(k<=25),
第二行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。
Output
输出只有一行,包含一个整数,表示最多能拦截多少枚导弹。
Sample Input
8
300 207 155 300 299 170 158 65
Sample Output
6
解题思路
由于拦截系统只能拦截从高到低的,而要将拦截系统使用最充分,则应该使拦截系统拦截系统拦截最多导弹,此时应该按导弹高度求出他的最长降序子序列。
因此可以用动态规划列出它的状态转移方程,然后进行求解。
LDS()函数的作用是求出以 mis[i] 结尾的最长降序序列长度。注意因为问题中导弹高度是后一个导弹不高于前一个导弹的高度,所以mis[i] <= mis[j],然后依次比较求出最大值。
具体实现代码如下,
#include<bits\stdc++.h>
using namespace std;
int mis[30]; //导弹高度
int dp[30]; //存取序列的长度
int k;
int ans = 0;
void LDS()
{
for(int i = 0; i < k; i++) //以a[i]结尾的元素的最长长度
{
dp[i] = 1; //若此元素为最小,则最长需陈列长度为1,赋予默认值1
for(int j = 0; j < i; j++) //求出以a[i]结尾的最长降序子序列长度 从头到尾开始检查每一个元素
{
if(mis[i] <= mis[j]) // 若i元素小于j元素 即他们之间的关系为降序
dp[i] = max(dp[i], dp[j]+1);
}
ans = max(ans, dp[i]); //确定最长降序序列长度
}
}
int main()
{
scanf("%d",&k);
for(int i = 0;i < k; i++)
scanf("%d", &mis[i]); //输入导弹高度
//求出一个由高向低排列最长的序列 即后一个元素只能小于或等于前一个元素 即求出LDS
LDS();
printf("%d", ans);
}