【ACWing】187. Missile Defense System

Subject address:

https://www.acwing.com/problem/content/189/

In order to counter the threat of malicious countries nearby, a certain country updated its missile defense system. The missile interception height of a defensive system has always been strictly monotonously increasing or has been strictly monotonously decreasing. For example, a system has intercepted a height of 3 33 and height is4 44 missiles, then the system can only intercept more than4 44 missiles. Given the height of a series of upcoming missiles, please find out at least how many sets of defense systems are needed to shoot them all down.

Input format: The
input contains multiple sets of test cases. For each test case, the first line contains the integer nnn indicates the number of incoming missiles. The second line containsnnn different integers, representing the height of each missile. When entering a test casen = 0 n=0n=When 0 , it means that the input is terminated, and the use case does not need to be processed.

Output format:
For each test case, output an integer that occupies a row to indicate the number of defense systems required.

Data range:
1 ≤ n ≤ 50 1≤n≤501n50

In fact, it is asking how many strictly monotonic subsequences can be divided into at least an array. For the case of only being divided into strictly ascending sub-sequences, you can use the anti-chain decomposition theorem to do it. For the theorem and algorithm, please refer to https://blog.csdn.net/qq_46105170/article/details/108616895 . But here needs to be classified into two sub-sequences, only DFS can be used to violently enumerate each number xxx should be added to the ascending subsequence or the descending subsequence. code show as below:

#include <iostream>
using namespace std;

const int N = 35;
int n;
int a[N];
// up存的是严增子序列分解的每个序列的最后一个数,
// down是严降子序列分解的每个序列的最后一个数
int up[N], down[N];
int res;

void dfs(int u, int su, int sd) {
    
    
	// 如果深度大于等于了之前找到的解,那就没必要搜了
    if (su + sd >= res) return;
    // 搜到一个解,则更新答案
    if (u == n) {
    
    
        res = su + sd;
        return;
    }
	
	// 二分严增子序列末尾,找到第一个小于a[u]的数的位置(up数组是单调降的)
    int l = 0, r = su - 1;
    while (l < r) {
    
    
        int m = l + (r - l >> 1);
        if (up[m] < a[u]) r = m;
        else l = m + 1;
    }

	// 找不到则新开一个序列,继续搜索;否则覆盖掉二分找到的位置,继续搜索
    if (l > r || up[l] >= a[u]) {
    
    
        up[su++] = a[u]; dfs(u + 1, su, sd); su--;
    } else {
    
    
        int t = up[l]; up[l] = a[u]; dfs(u + 1, su, sd); up[l] = t;
    }

	// 类似上面,down数组是单调增的,找到第一个大于a[u]的位置
    l = 0, r = sd - 1;
    while (l < r) {
    
    
        int m = l + (r - l >> 1);
        if (down[m] > a[u]) r = m;
        else l = m + 1;
    }

    if (l > r || down[l] <= a[u]) {
    
    
        down[sd++] = a[u]; dfs(u + 1, su, sd); sd--;
    } else {
    
    
        int t = down[l]; down[l] = a[u]; dfs(u + 1, su, sd); down[l] = t;
    }
}

int main() {
    
    
    while (cin >> n, n) {
    
    
        for (int i = 0; i < n; i++) cin >> a[i];

        res = n;
        dfs(0, 0, 0);

        cout << res << endl;
    }

    return 0;
}

Time complexity O (2 n log ⁡ n) O(2^n\log n)O ( 2nlogn ) (there are not so many, depending on the specific data), spaceO (n) O(n)O ( n )

Guess you like

Origin blog.csdn.net/qq_46105170/article/details/114223597