题目
拦截导弹
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹,拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此不可能拦截所有的导弹。输入----导弹依次飞来的高度,不大于 30000 的正整数
389 207 155 300 299 170 158 65
输出----这套系统最多能拦截的导弹数和拦截所有导弹所需最少的拦截系统数
6
2
算法分析
**问题抽象:**求最多可以拦截的导弹数,就是求最长递减字串长度,这个很好理解
求最少的系统数,就是求最长非递减字串的长度,可以这样理解,假设最长的非递减字串长度为n, 那么以这最长的非递减字串的每个字符为分界点,可以将整个串分成n个小递减的小字串,这样每一发炮弹都可以拦截对应的小字串,倘若最长的非递减字串长大于n, 那么势必会有一个小字串不是递减的,则这个字串就要用不止一发子弹才能打下。
算法: 以最长递减字串为例,就是求以每个字符结尾字串中最长的,以字符i结尾的字符串可以这样表示
这里j<i
利用动态规划自低向下的从0一直到n-1进行上述操作,最后在找出dp[i]最大的就行。
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 9999
int down[N];//down[i]表示以i+1个字符结尾的最长递减子序列
int up[N];//up[i]表示以i+1个字符结尾的最长非递减子序列
int h[N];//表示高度
int n=0;
int main(){
while(cin>>h[n++]);
n--;
for(int i;i<n;i++)
down[i]=up[i]=1;//最坏情况下自身也是一个串
for(int i=0;i<n;i++)
{
for(int j=0;j<i;j++)
{
if(h[i]<h[j])
down[i]=max(down[i],down[j]+1);
else
up[i]=max(up[i],up[j]+1);
}
}
int maxd=0,maxu=0;
for(int i=0;i<n;i++){
maxd=max(maxd,down[i]);
maxu=max(maxu,up[i]);
}
cout<<maxd<<endl<<maxu<<endl;
return 0;
}
时间复杂度
O(n2)