

导弹拦截
本题的第一问为最长不上升子序列,重点在于第二问。
第二问可分为两种做法
1.贪心做法
用如下方式维护数组g,数组长度cnt,意为cnt个不下降子序列。保存的是每一个不上升子序列中的最后一个数:
遍历原序列,对于遍历到的每一个数x:
1.若x大于g中每一个数,则新建一个不上升子序列,放入x;
2.否则,找到g中大于等于x的最小的数,将其替换。
由于g每次增加长度时,增加的数必然大于其前面g中的任何一个数;且每次替换时,不改变x与被替换数左右相邻两数的相对大小关系,故g必然维持单调递增。则g即为原序列的最长上升子序列。
int cnt=0; //数组g记录的是每个不升序列结尾的最小值
for(int i=0;i<cnt;i++)
{
int k=0;
while(k<cnt&&a[i]>g[k]) k++;
g[k]=a[i];
if(k==cnt) cnt++;
}
2.运用Dilworth定理做法:
原链最长长度=反链划分数最小值
何为反链?
最长上升子序列<=>不升子序列最小划分数
最长下降子序列<=>不降子序列最小划分数
本题要求的是不升子序列即将题目转化为求上升子序列即可。
for(int i=0;i<cnt;i++)
{
f[i]=1;
for(int j=0;j<i;j++)
if(a[i]>a[j])
f[i]=max(f[i],f[j]+1);
res=max(f[i],res);
}
cout<<res;
本文探讨了导弹拦截问题的两种算法实现方法:贪心算法和基于Dilworth定理的方法。贪心算法通过维护一系列不下降子序列来寻找最长上升子序列,而Dilworth定理方法则将问题转化为寻找最长上升子序列的等价问题。

被折叠的 条评论
为什么被折叠?



