题目要求输出最多能拦截的导弹数与拦截全部导弹最少系统配备数;
显然最多能拦截的导弹数即为最长非上升子序列;分析可得拦截全部导弹最少系统配备数为最长上升子序列个数;
设系统最少配备数为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; }