题目大意:输入n表示测试用例数,接着输入p,表示连接端口数,之后输入p行端口号,表示左侧第i个端口要连接的右侧的哪个端口,要求所有的端口两线不能相交,求出最多的端口连线的数目。
算法思想:
此题的本质就是求最长上升子序列,但算法的复杂度要求为O(nlogn)。用一个数组b[i]记录当序列长度为i的时候第i个元素的最小值。在算法过程中b[]是不断动态更新的,当a[i]>=b[k]时,b[k+1]=a[i],当a[i]小于b[k]时寻找其在b[]中的位置pos并且更行b[pos]。最后b[]的规模k就是最长上升子序列的长度。
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=40010;
int a[MAXN];
int b[MAXN];/*b[]一直进行动态更新*/
/*在b[]中寻找a[i]的位置*/
int Binary_Search(int num,int k){
int l=1,r=k;
while(l<=r){
int m=(l+r)/2;
if(num>=b[m])
l=m+1;
else
r=m-1;
}
return l;
}
/*最长的公共子序列*/
int LIS(int c[],int N){
int k=1;
b[1]=a[1];
for(int i=2;i<=N;i++){
if(a[i]>=b[k])
b[++k]=a[i];
else{
int pos=Binary_Search(a[i],k);
b[pos]=a[i];
}
}
return k;
}
int main(){
int n,p;
cin>>n;
while(n--){
int p;
cin>>p;
for(int i=1;i<=p;i++){
cin>>a[i];
}
cout<<LIS(a,p)<<endl;
}
return 0;
}