题目描述:
为了对抗附近恶意国家的威胁,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;
}
来源:CSDN
作者:昂昂累世士
链接:https://blog.csdn.net/qq_30277239/article/details/104060851