为了对抗附近恶意国家的威胁,R 国更新了他们的导弹防御系统。
一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。
例如,一套系统先后拦截了高度为 3 和高度为 4 的两发导弹,那么接下来该系统就只能拦截高度大于 4 的导弹。
给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。
输入格式
输入包含多组测试用例。
对于每个测试用例,第一行包含整数 n,表示来袭导弹数量。
第二行包含 n 个不同的整数,表示每个导弹的高度。
当输入测试用例 n=0 时,表示输入终止,且该用例无需处理。
输出格式
对于每个测试用例,输出一个占据一行的整数,表示所需的防御系统数量。
数据范围
1≤n≤50
输入样例:
5
3 5 2 4 1
0
输出样例:
2
样例解释
对于给出样例,最少需要两套防御系统。
一套击落高度为 3,4 的导弹,另一套击落高度为 5,2,1 的导弹。
这道题的题意是求覆盖最长上升子序列和最长下降子序列的个数。
我们单个求最长上升子序列有一个固定的模板。
for(int i=0;i<n;i++)
{
int k=0;
while(k<cnt&&t[k]<p[i]) k++;
t[k]=p[i];
if(k>=cnt)
cnt++;
}
要是想求覆盖二者的最小区间数,目前y总说没有想到很好的办法,然后他用了爆搜的方法去做,我们首先一一枚举,我们先分开枚举是放到上升子序列还是放到下降子序列,所以我们先枚举上升,在枚举下降,最后我们可以得出结论,因为递归的特性,所以我们可以枚举2n的所有可能,然后需要注意的地方是,我第一次写爆搜代码的时候,我仔细的检查了一遍我的第一次代码。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=55;
int q[N],up[N],down[N];
int ans;
int n;
void dfs(int u,int su,int sd)
{
if(su+sd>ans)
return ;
if(u==n)
{
ans=min(ans,su+sd);
return;
}
int k=0;
while(k<su&&up[k]>=q[u]) k++;
int t=up[k];
up[k]=q[u];
if(k<su) dfs(u+1,su,sd);
else dfs(u+1,su+1,sd);
up[k]=t;
k=0;
while(k<sd&&down[k]<=q[u]) k++;
t=down[k];
down[k]=q[u];
if(k<sd) dfs(u+1,su,sd);
else dfs(u+1,su,sd+1);
down[k]=t;
}
int main(void)
{
while(cin>>n,n)
{
for(int i=0;i<n;i++) cin>>q[i];
ans=n;
dfs(0,0,0);
cout<<ans<<endl;
}
}
这个是错误代码,我TLE了,我刚开始也是debug了很多次,
最后败在了一个小细节,当我们dfs的时候,尽可能多的去剪枝,减少条件。
我在
if(su+sd>=ans)
return;
这个条件上少加了一个等号,我以为没什么,仔细想了想会增加计算量,这个能去就去。
dfs本身就是时间复杂度很大的算法,所以我们要想办法去除。
最终代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=55;
int q[N],up[N],down[N];
int ans;
int n;
void dfs(int u,int su,int sd)
{
if(su+sd>=ans)
return;
if(u==n)
{
ans=min(ans,su+sd);
return;
}
int k=0;
while(k<su&&up[k]>=q[u]) k++;
int t=up[k];
up[k]=q[u];
if(k<su) dfs(u+1,su,sd);
else dfs(u+1,su+1,sd);
up[k]=t;
k=0;
while(k<sd&&down[k]<=q[u]) k++;
t=down[k];
down[k]=q[u];
if(k<sd) dfs(u+1,su,sd);
else dfs(u+1,su,sd+1);
down[k]=t;
}
int main(void)
{
while(cin>>n,n)
{
for(int i=0;i<n;i++) cin>>q[i];
ans=n;
dfs(0,0,0);
cout<<ans<<endl;
}
}