【题目描述】
1260:【例9.4】拦截导弹(Noip1999)
【题目描述】
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
【输入】
输入导弹依次飞来的高度。
【输出】
第一行:最多能拦截的导弹数;
第二行:要拦截所有导弹最少要配备的系统数。
【输入样例】
389 207 155 300 299 170 158 65
【输出样例】
6
2
【思路】
思路其实很简单,但是前提是需要看出题目考察的是最长上升子序列和最长不上升子序列,但是当我知道该题所考察的内容时,有一个疑问,为什么最长上升子序列的长度就是要拦截所有导弹最少要配备的系统数?我觉得应该会有人会有和我相似的疑惑,所以就想把自己的心得写下来,废话不多说。
首先,大家要先知道一个定理,有助于大家理解:就是Dilworth定理,其实定理具体讲什么东西大家不必关心,当然有兴趣的朋友也可以去百度一下:我们要用到定理中的东西就是:链的最少划分数 = 反链的最长长度,这里的链的最少划分数就是要拦截所有导弹最少要配备的系统数,链就是不上升子序列,反链就是上升子序列;光看这些东西还是有些晦涩难懂,我们来证明一下,如果导弹高度序列中的上升子序列最大长度为X,要拦截所有导弹要配备的系统数为Y,题目要求每一发炮弹都不能高于前一发的高度一旦高于就需要新增一套系统,所以Y>=X,题目又要求系统数最少,所以Y最少就是等于X;
感谢阅读,希望可以帮助到与我有相似疑惑的人,下面附上代码
【AC代码】
#include<bits/stdc++.h>
using namespace std;
int main()
{
int data[1005];
int k=0;
while(scanf("%d",&data[k++])!=EOF);
k--;//结束输入时的一次输入也被算在其中,所以k要--,比较菜之前
//被卡在这
int maxup[1005],maxdown[1005];
fill(maxup,maxup+1005,1);
fill(maxdown,maxdown+1005,1);
int ans1=-1,ans2=-1;
for(int i=0;i<k;i++)
{
for(int j=0;j<i;j++)
{
if(data[i]>data[j])
{
maxup[i]=max(maxup[i],maxup[j]+1);
}
else
{
maxdown[i]=max(maxdown[i],maxdown[j]+1);
}
}
ans1=max(ans1,maxup[i]);
ans2=max(ans2,maxdown[i]);
}
cout<<ans2<<'\n'<<ans1;
return 0;
}