- 题目描述:
-
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
- 输入:
-
每组输入有两行,第一行,输入雷达捕捉到的敌国导弹的数量k(k<=25),
第二行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。
- 输出:
-
每组输出只有一行,包含一个整数,表示最多能拦截多少枚导弹。
- 样例输入:
-
8 300 207 155 300 299 170 158 65
- 样例输出:
-
6
分析:很明显该题的核心问题的是求得一个最大高度,使其满足可以拦截最多的导弹。因为拦截系统每次的拦截高度是递减的,那么这就是最长不增子序列。依然可以运用下面的推导公式:
F[1] = 1;
F[i] = max{1,F[j] + 1|j<i && a[j]>=a[i]};
代码实现:#include <iostream> using namespace std; const int MAXSIZE = 25; const int MIN = 0; int arr[MAXSIZE]; int F[MAXSIZE]; int main() { int k; int maxLen; while (cin >> k) { memset(F, 0, MAXSIZE); F[0] = 1; for (int i = 0; i < k; i++) { cin >> arr[i]; F[i] = 1; } for (int i = 1; i < k; i++) { maxLen = MIN; for (int j = 0; j < i; j++) { if (arr[i] <= arr[j] && maxLen < F[j]) { maxLen = F[j]; } } F[i] = maxLen + 1; } maxLen = F[0]; for (int t = 1; t < k; t++) if (F[t] > maxLen ) maxLen = F[t]; cout << maxLen << endl; } }
扩展一下,如果需要打印拦截的所有导弹的高度。那么可以增加一个路径数组,用来记录每次选择的中间点。easy,代码如下:
#include <iostream> using namespace std; const int MAXSIZE = 25; const int MIN = 0; int arr[MAXSIZE]; int F[MAXSIZE]; int path[MAXSIZE];//存储路径 int main() { int k; int maxLen; int index; while (cin >> k) { memset(F, 0, MAXSIZE); F[0] = 1; for (int i = 0; i < k; i++) { cin >> arr[i]; F[i] = 1; path[i] = i; } for (int i = 1; i < k; i++) { maxLen = MIN; for (int j = 0; j < i; j++) { if (arr[i] <= arr[j] && maxLen < F[j]) { maxLen = F[j]; index = j; } } F[i] = maxLen + 1; path[i] = index; } maxLen = F[0]; for (int t = 1; t < k; t++) if (F[t] > maxLen) { maxLen = F[t]; index = t; } cout << maxLen << endl; while (F[index] != 1) { cout << arr[index] << ' '; index = path[index]; } cout << arr[index] << endl; } }