NOI 8780 拦截导弹 线性dp

总时间限制: 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;
}
发布了19 篇原创文章 · 获赞 0 · 访问量 500

猜你喜欢

转载自blog.csdn.net/qq_43317133/article/details/99690719