LGp1020-导弹拦截

题目链接

题目要求输出最多能拦截的导弹数与拦截全部导弹最少系统配备数;

显然最多能拦截的导弹数即为最长非上升子序列;分析可得拦截全部导弹最少系统配备数为最长上升子序列个数;

设系统最少配备数为a,则有a个非上升子序列,任取其中俩子序列c,d,c中必存在某数大于d中某数,否则c,d应归为一个序列,那么我们可以从这a个序列中各取一数得到一最长上升子序列,若此上升子序列个数小于题目所给初始序列的最长上升子序列数m即意味着有两个数在同一个非上升序列中,不符合非上升序列的定义,故a=m;

解法1:动态规划 (时间复杂度O(n2))

#include<iostream>
using namespace std;
int h[100005],d[100005],a[100005];
int main(){
    int n=0,ans1=0,ans2=0;
    while(cin>>a[n++]);n--;
    for(int i=0;i<n;i++) {h[i]=1;d[i]=1;}
    for(int i=1;i<n;i++)
        for(int k=0;k<i;k++){
            if(a[i]>a[k]&&h[i]<h[k]+1)
            h[i]=h[k]+1;
            if(a[i]<=a[k]&&d[i]<d[k]+1)
            d[i]=d[k]+1;
        }
        for(int i=0;i<n;i++){
            ans1=max(ans1,d[i]);
            ans2=max(ans2,h[i]);
        }
        cout<<ans1<<endl<<ans2<<endl;
return 0;
}

解法2:lower_bound(),upper_bound() (时间复杂度O(nlog2n))

lower_bound(),upper_bound()为二分搜索,因要求非上升序列,故upper_bound()加入great<int>即改为找数组中第一个小于对应数的地址

#include<iostream>
#include<algorithm>
using namespace std;
int h[100005],d[100005],a[100005];
int main(){
    int n=0,ans1=0,ans2=0;
    while(cin>>a[n++]);n--;
    h[0]=a[0];d[0]=a[0];
    for(int i=1;i<n;i++){
        if(a[i]<=d[ans1])
            d[++ans1]=a[i];
        else
            *upper_bound(d,d+ans1+1,a[i],greater<int>())=a[i];
        if(a[i]>h[ans2])
            h[++ans2]=a[i];
        else
            *lower_bound(h,h+ans2+1,a[i])=a[i];

    }
        cout<<ans1+1<<endl<<ans2+1<<endl;
return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/WELOTX/p/11297620.html