导弹防御系统

导弹防御系统

为了对抗附近恶意国家的威胁,$R$ 国更新了他们的导弹防御系统。

一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。

例如,一套系统先后拦截了高度为 $3$ 和高度为 $4$ 的两发导弹,那么接下来该系统就只能拦截高度大于 $4$ 的导弹。

给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。

输入格式

输入包含多组测试用例。

对于每个测试用例,第一行包含整数 $n$,表示来袭导弹数量。

第二行包含 $n$ 个不同的整数,表示每个导弹的高度。

当输入测试用例 $n=0$ 时,表示输入终止,且该用例无需处理。

输出格式

对于每个测试用例,输出一个占据一行的整数,表示所需的防御系统数量。

数据范围

$1 \leq n \leq 50$

输入样例:

5
3 5 2 4 1
0 

输出样例:

2

样例解释

对于给出样例,最少需要两套防御系统。

一套击落高度为 $3,4$ 的导弹,另一套击落高度为 $5,2,1$ 的导弹。

 

解题思路

  这题与拦截导弹很像,不过这题可以用严格单调下降的子序列与严格单调上升的子序列把原序列覆盖住,问需要这两种子序列的最少个数。这题与拦截导弹的做法几乎一样,用贪心的做法把当前数接到某个子序列后面。

  对于每一个数,我们不知道应该将它放大上升的子序列中,还是放到下降的子序列中,因此需要爆搜。

  对于单调下降的子序列已经在拦截导弹这题中给出证明,单调上升的子序列的证明类似。可以证明如果用数组$up \left[ ~ \right]$来存放每一个单调上升的子序列的结尾的那个数,$up$数组一定是一个单调递减的数组,从头开始遍历$up \left[ ~ \right]$找到第一个小于当前数的子序列。

  深搜求最小值有两种方法,一种是用一个全局变量来维护搜索过程中的最小值,另一种方法是迭代加深。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 60;
 5 
 6 int n;
 7 int a[N], up[N], down[N];
 8 int ans;
 9 
10 void dfs(int u, int su, int sd) {
11     if (su + sd >= ans) return;
12     if (u == n) {
13         ans = su + sd;
14         return;
15     }
16     
17     // 把这个当前数放到上升的子序列中
18     int k = 0;
19     while (k < su && up[k] >= a[u]) {
20         k++;
21     }
22     int t = up[k];
23     up[k] = a[u];
24     if (k == su) dfs(u + 1, su + 1, sd);
25     else dfs(u + 1, su, sd);
26     up[k] = t;
27     
28     // 把这个当前数放到下降的子序列中
29     k = 0;
30     while (k < sd && down[k] <= a[u]) {
31         k++;
32     }
33     t = down[k];
34     down[k] = a[u];
35     if (k == sd) dfs(u + 1, su, sd + 1);
36     else dfs(u + 1, su, sd);
37     down[k] = t;
38 }
39 
40 int main() {
41     while (scanf("%d", &n), n) {
42         for (int i = 0; i < n; i++) {
43             scanf("%d", a + i);
44         }
45         
46         ans = N;
47         dfs(0, 0, 0);
48         printf("%d\n", ans);
49     }
50     
51     return 0;
52 }

  迭代加深的代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 60;
 5 
 6 int n;
 7 int a[N], up[N], down[N];
 8 int ans;
 9 
10 bool dfs(int u, int su, int sd, int dep) {
11     if (su + sd > dep) return false;
12     if (u == n) return true;
13     
14     int k = 0;
15     while (k < su && up[k] >= a[u]) {
16         k++;
17     }
18     int t = up[k];
19     up[k] = a[u];
20     if (dfs(u + 1, su + (k == su), sd, dep)) return true;
21     up[k] = t;
22     
23     k = 0;
24     while (k < sd && down[k] <= a[u]) {
25         k++;
26     }
27     t = down[k];
28     down[k] = a[u];
29     if (dfs(u + 1, su, sd + (k == sd), dep)) return true;
30     down[k] = t;
31     
32     return false;
33 }
34 
35 int main() {
36     while (scanf("%d", &n), n) {
37         for (int i = 0; i < n; i++) {
38             scanf("%d", a + i);
39         }
40         
41         int dep = 1;
42         while (!dfs(0, 0, 0, dep)) {
43             dep++;
44         }
45         printf("%d\n", dep);
46     }
47     
48     return 0;
49 }

 

参考资料

  AcWing 187. 导弹防御系统(算法提高课):https://www.acwing.com/video/365/

posted @ 2022-07-27 23:24  onlyblues  阅读(337)  评论(0编辑  收藏  举报
Web Analytics