点击打开链接(新发现的一个oj,样式很小清新呀)
题目大意:n个导弹,(1)求最大非上升子序列长度(2)要拦截所有导弹最少要配备这种导弹拦截系统的套数
思路1:每一次求最大非上升子序列,求一次删一次。直到数组全0。有点害怕超时,然而没有hhh
注意:
1、需要记录序列不能用O(nlogn)的方法
2、lower_bound()函数的要求是查找数组是非递减的,找第一个>=x的位置;upper_bound(a.begin(),a.end(),x)求求非递减数组中第一个>x的位置
3、剔除元素后,内外循环都要判断a[i]==0
4、使用memset要加头文件<string.h>(vs中不会出错,但是oj会bug)
5、剔除元素判断必须用dp[j],用pre[j]最后一个元素剔除不了
思路2:(2)是求最大上升子序列(参考,虽然没很懂,但是记住这个定理吧,可以套模板)
两个定理:定理1 令(X,≤)是一个有限偏序集,并令r是其最大链的大小。则r为X的最大反链数。
对偶定理:对于一个偏序集,其最少反链划分数等于其最长链的长度。这就是Dilworth定理。
思路1代码:(思路2就不敲了。。。)
#include<iostream> #include<algorithm> #include<string.h>//第n+1次忘了这个。。。 using namespace std; int a[1001],pre[1001],dp[1001]={0}; int main() { int i,k,M,Mindex,j,count,n=0; cin>>k; for (i=1;i<=k;i++) cin>>a[i]; count=k; while(count)//数组中非0个数 { n++; M=0; memset(dp,0,sizeof(dp)); memset(pre,0,sizeof(dp)); for (i=k;i>=0;i--) { if (a[i]==0)continue;//忽略已删除元素 for (j=k;j>i;j--) { if (a[j]==0) continue;//不能忘记!!!!!里面也要判断一次 if ( a[j]<=a[i] && dp[j]>dp[i]) { dp[i]=dp[j]; pre[i]=j;//记录序列 } } dp[i]++; if (dp[i]>M) { M=dp[i]; Mindex=i; } } if (count==k)//输出第一次求得的序列长 cout<<M<<" "; j=Mindex; while(dp[j])//剔除本次求得的序列元素,不能用pre[j] { a[j]=0; j=pre[j]; count--; } } cout<<n<<endl; return 0; }