总时间限制: 1000ms 内存限制: 65536kB
描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹。
输入
第一行是一个整数N(不超过15),表示导弹数。
第二行包含N个整数,为导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数)。
输出
一个整数,表示最多能拦截的导弹数。
样例输入
8
389 207 155 300 299 170 158 65
样例输出
6
这是一题线性dp的基础题,甚至可以算这一类题目的模板题,所以写一下以后回来参考。
题目本身没有难度,求的是最长非上升子序列,以后求什么最长上升子序列、最长下降子序列都用得到这一题的代码,所以直接上代码,注释我想已经够清楚了。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
#include <string.h>
const int MAX=1e6+5;
using namespace std;
int h[2000], d[2000], n, c;
int main()
{
cin >> n;
for (int i=0; i<n; i++)
scanf("%d", &h[i]);
d[0] = h[0]; /// d的第一个先记为第一个飞入的导弹
c = 1; /// 先设拦截下了第一颗
int i, j;
for (i=1; i<n; i++) /// 从h的第1位开始遍历
{
for (j=c-1; j>=0; j--) /// 从d中目前最优解c,-1的位置回溯
if (h[i]<=d[j]) /// 找到d中>=h[i]的位置就跳出
break;
d[j+1] = h[i];/// 在d回溯过程中第一个>=h[i]的位置后换上h[i]
if (j==c-1) c ++;/// 如果回溯过程是第一次就直接跳出了,证明当前导弹直接满
///足上一个状态最长子序列的排列,所以它相当于直接接续在
///上一状态最长子序列的后面,使其+1成为当前最长子序列
}
/// 实在理解不了咱再模拟一手案例,结合一下代码就很好理解为什么最后输出c了
///389 207 155 300 299 170 158 65 c=1
///389 0 0 0 0 0 0 0 c=1
///389 207 0 0 0 0 0 0 c=2
///389 207 155 0 0 0 0 0 c=3
///389 300 155 c=3
///389 300 299 c=3
///389 300 299 170 c=4
///389 300 299 170 158 c=5
///389 300 299 170 158 65 c=6
cout << c << endl;
}