AcWing 187 导弹防御系统

会有一股神秘感。 提交于 2020-01-22 03:31:11

题目描述:

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

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

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

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

输入格式

输入包含多组测试用例。

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

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

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

输出格式

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

数据范围

1≤n≤50

输入样例:

5
3 5 2 4 1
0 

输出样例:

2

样例解释

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

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

分析:

如果所有导弹防御系统拦截高度都是严格单调上升的,我们采取贪心的思路就是,如果所有系统的最小高度均不小于当前飞来导弹的高度,则新建一套系统;如果存在小于当前导弹高度的系统,则选择其中正确发射导弹高度最高的那个去击落该导弹。转换成LIS就是,如果当前上升子序列中所有序列的末元素均不小于遍历到的元素,则新建一个上升子序列;如果所有上升子序列中存在末元素小于遍历到的元素,则将该元素加到末字符最大的那个上升子序列的末尾。

如果所有导弹防御系统拦截高度都是严格单调下降的,贪心的思路就是,如果当前下降子序列中所有序列的末元素均不大于遍历到的元素,则新建一个下降子序列;如果所有下降子序列中存在末元素大于遍历到的元素,则将该元素加到末字符最小的那个下降子序列的末尾。

本题要求两类系统数总和最小。飞来一个导弹,我们不知道使用上升的导弹防御系统还是下降的导弹防御系统号,因此,只能都尝试下,采用dfs遍历每一种选择。需要注意的是,我们在选择将某个元素加到LIS末尾后,如果再要选择不加入LIS末尾,则需要恢复全局变量,以便加入到下降子序列末尾。

dfs的三个参数分别为:cur-当前遍历到的导弹高度,si-现有递增子序列的数量,sd-现有下降子序列的数量。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 55;
int n,ans,a[N],f[N],g[N];
void dfs(int cur,int si,int sd){
    if(si + sd >= ans) return;//剪枝
    if(cur == n){//导弹击落完了
        ans = si + sd;
        return;
    }
    //选择上升导弹防御系统
    int j = 0;
    while(j < si && f[j] >= a[cur]) j++;
    int t = f[j];
    f[j] = a[cur];
    if(j >= si)  dfs(cur + 1,si + 1,sd);//新建一个上升导弹防御系统
    else    dfs(cur + 1,si,sd);//不新建系统
    f[j]= t;//恢复全局变量
    //选择下降导弹防御系统
    j = 0;
    while(j < sd && g[j] <= a[cur]) j++;
    t = g[j];
    g[j] = a[cur];
    if(j >= sd)  dfs(cur + 1,si,sd + 1);
    else    dfs(cur + 1,si,sd);
    g[j]= t;
}
int main(){
    while(cin>>n,n){
        for(int i = 0;i < n;i++)    cin>>a[i];
        ans = n;
        dfs(0,0,0);
        cout<<ans<<endl;
    }
    return 0;
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!