最长公共子序列的nlogn算法——bsoj1139

来源:互联网 发布:centos iso镜像下载64 编辑:程序博客网 时间:2024/04/30 04:30

#include<iostream>#include<algorithm>#include<cstring>#include<cstdio> using namespace std; int n,i,f[100000+9],a[100000+9],b[100000+9];int x;int main(){while(cin>>n){for(int i=1;i<=n;i++){scanf("%d",&x);a[x]=i;}for(int i=1;i<=n;i++){scanf("%d",&x);b[a[x]]=i;}f[1]=b[1];int len=1;for(int i=2;i<=n;i++)if(b[i]>f[len])f[++len]=b[i];else{int l=1,r=len,mid;while(l<=r){mid=(l+r)/2;if(f[mid]<b[i])l=mid+1;elser=mid-1;}f[l]=b[i];}printf("%d\n",len);}return 0;}

没有效率的没有效率。。。

好吧我以后尽量不在题解里吐槽了。。。

做完nlogn的lis当然马上就要用lis在nlogn时间里求lcs了呀。。

————————————————以下为题解——————————————————————————————-————————————————————————

在James W. Hunt和Thomas G. Szymansky 的论文"A Fast Algorithm for Computing Longest Common Subsequence"中,给出了O(nlogn)下限的一种算法。

 

定理:设序列A长度为n,{A(i)},序列B长度为m,{B(i)},考虑A中所有元素在B中的序号,即A某元素在B的序号为{Pk1,Pk2,..},将这些序号按照降序排列,然后按照A中的顺序得到一个新序列,此新序列的最长严格递增子序列即对应为A、B的最长公共子序列。

 

举例来说,A={a,b,c,d,b},B={b,c,a,b},则a对应在B的序号为2,b对应序号为{4,0},c对应序号为1,d对应为空集,生成的新序列为{2,4, 0, 1, 4, 0},其最长严格递增子序列为{0,1,4},对应的公共子序列为{b, c, b}

 

原论文的证明过程较复杂,其实可以简单的通过一一对应来证明。即证明A、B的一个公共子序列和新序列的一个严格递增子序列一一对应。

(1) A、B的一个公共子序列对应新序列的一个严格递增子序列

假设A、B的某一个公共子序列长度为k,则其公共子序列在A和B中可以写为

{Ai1,Ai2, ..., Aik}

{Bj1,Bj2, ..., Bjk}

 

如此有Ai1 = Aj1,Ai2 = Aj2, ...., Aik = Ajk, 考虑元素Bj1在B中的序号P(Bj1),则有

P(Bj1)< P(Bj2) < ... < P(Bjk)

注意此严格递增子序列属于新序列的一个子序列,因此得证

 

(2) 新序列的一个严格递增子序列对应A、B的一个公共子序列

设新序列的一个严格递增子序列{P1,P2, ..., Pk},任意两个相信的P不可能属于A中同一个元素,因为A中某元素在B中的序号按照降序排列,但此序列为严格递增序列,矛盾。所以每个P均对应于A中不同位置的元素,设为{Ai1, Ai2, ..., Aik}。

因为P是严格递增序列,则每个P也对应B中唯一的一个元素,假设为{Bj1,Bj2, ..., Bjk},由P的定义可知Ai1= Aj1, Ai2 = Aj2, ...., Aik = Ajk,因此得证。

 

实现上比较复杂,有以下几个步骤:

(1) 对序列B排序

(2) 计算A中每个元素在B中的序号,并构成新序列

(3) 使用LIS的方法计算最长严格递增子序列

(4) 获取最长公共子序列



0 0
原创粉丝点击