题目链接:
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。 某天,雷达捕捉到敌国的导弹来袭。 由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。 输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。 输入格式 共一行,输入导弹依次飞来的高度。 输出格式 第一行包含一个整数,表示最多能拦截的导弹数。 第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。 数据范围 雷达给出的高度数据是不大于 30000 的正整数,导弹数不超过 1000。 输入样例: 389 207 155 300 299 170 158 65 输出样例: 6 2
第一问就是很朴素的最长下降子序列:
第二问是贪心算法:
假设当前以及配置了N个导弹系统且当前枚举的数为x,则在前面N个导弹系统中找出小于等于x的最大的那个数将x放在它的后面,若找不到这样的数则多加一个导弹系统;
可以看出第二问等价于求最长上升子序列:
#include <cstdio> #include <cstring> #include <sstream> #include <iostream> using namespace std; const int N = 1010; int n; int a[N]; int q[N]; int f[N], g[N]; int main() { string line; getline(cin, line); stringstream ssin(line); while (ssin >> a[n]) n ++ ; int len = 0;//求最长下降子序列 for (int i = 0; i < n; i ++ ) { int l = 0, r = len; while (l < r) { int mid = l + r + 1 >> 1; if (a[i] <= q[mid]) l = mid; else r = mid - 1; } len = max(len, r + 1); q[r + 1] = a[i]; } cout << len << endl; len = 0;//求最长上升子序列 memset(q, 0, sizeof q); for (int i = 0; i < n; i ++ ) { int l = 0, r = len; while (l < r) { int mid = l + r + 1 >> 1; if (a[i] > q[mid]) l = mid; else r = mid - 1; } len = max(len, r + 1); q[r + 1] = a[i]; } cout << len << endl; }