某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。

但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。

某天,雷达捕捉到敌国的导弹来袭。

由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式

共一行,输入导弹依次飞来的高度。

输出格式

第一行包含一个整数,表示最多能拦截的导弹数。

第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。

输入样例:

389 207 155 300 299 170 158 65

输出样例:

6
2

分析:
这道题的题意就是,找单调下降最长的长度,然后如果第一遍找不完,再从剩下的导弹高度里边在进找,直到找到所有严格单调下降的导弹高度,并统计找的次数

换句人话--->用多少个单调下降子序列把完整的序列覆盖掉

贪心的流程:
  从前往后扫描每个数:
    case 1:如果现有的子序列都小于当前的数,就创建一个新的子序列
    case 2:将当前数放在大于等于它的最小子序列后面

这个g[]数组 就相当于我们的子序列末尾的数,他要保证单调上升,而我们的a就是当前子序列末尾的大于等于x的最小值,也就是将x放在了子序列结尾大于等于x的子序列的后面,也就是a的后边;

这道题如果深挖的化有一个反链的叫做DailWorth定理,有兴趣的可以了解下,在这里我就不赘述了。

这里的输入比较特别可以参考下c++的stringstream

具体详解代码:

 1 #include<iostream>
 2 #include<algorithm>
 3
 4 using namespace std;
 5 const int N = 1010;
 6 int n;
 7 int q[N];
 8 int f[N],g[N];
 9
10 int main(){
11     while(cin >> q[n]) n++;
12     int res = 0;
13     for(int i = 0;i < n;i++){
14         f[i] = 1;
15         for(int j = 0;j < i;j++)
16             if(q[j] >= q[i]) f[i] = max(f[i],f[j] + 1);
17             res = max(res,f[i]);
18     }
19     cout << res << endl;
20
21     //用g[]数组存储我们当前现有的所有的子序列
22     //用cnt表示我们当前现有子序列的个数
23     int cnt  = 0;
24     //从前往后贪心一遍
25     for(int i = 0;i < n;i++){
26         int k = 0;//k表示我们从前往后找的序列
27         //只要我们没有遍历完所有的序列 并且 当前的序列的结尾小于我们当前的数,就k++
28         while(k < cnt && g[k] < q[i]) k++;//序列找完并且没有比序列最小值小的我们的序列就++
29         g[k] = q[i];//将大的q[i]交换到本来小的序列的位置上在进行判断
30         if(k >= cnt) //说明我们没有任何一个序列是大于我们的当前数的
31         //我们就开一个新的序列
32         cnt++;
33     }
34
35     cout << cnt;
36
37 }




02-01 06:19