您的位置:首页 > 其它

HDU 1950 Bridging signals 最长公共子序列(LIS)nlogn算法实现

2016-07-07 14:02 253 查看
d这个数组是用来存放最长公共子序列的,且是字典序最小的。

思路是当a数组中的数中寻找最长公共子序列时,假设dp[i]这个数组放的是以i结尾的最长公共子序列长度,那么假设dp[x]=dp[y]且x<y,那么x的潜力更大,因为可能有a[x]<a[z]<a[y]所以用d来记录时,当发现有更小的数时,那么就在这个d中找到该数存放的位置放进去(位置就是该数大于前一个,小于后一个,那么该数就把第一个大于他的数覆盖掉),这样做有利于如果下面的数中的如果有大于a[x] ,但小于a[y]的,如果替换掉了那么d数组的最后++len,把大于的数放进去,记录d数组长度的len也增加了,如果不替换的话,这个数就无法放到d数组最后,也就意味着纪录d(最长公共子序列)长度的len不会增加,那记录的就不是最长了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=40010;
int d[maxn];
int a[maxn];
int Binarysearch(int key,int low,int high)
{
int mid;
while(low<=high)
{
mid=(low+high)>>1;
if(key>d[mid]&&key<=d[mid+1])
return mid;
else if(key>d[mid])
low=mid+1;
else
high=mid-1;
}
return 0;
}
int LIS(int p)
{
d[1]=a[1];
int len=1;
int j;
for(int i=2;i<=p;i++)
{
if(a[i]>d[len])
j=++len;
else
j=Binarysearch(a[i],1,len)+1;
d[j]=a[i];
}
return len;
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int p;
scanf("%d",&p);
for(int i=1;i<=p;i++)
scanf("%d",&a[i]);
int len=LIS(p);
printf("%d\n",len);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: