最长公共子序列的另一类优化方法
来源:互联网 发布:ubuntu怎么添加输入法 编辑:程序博客网 时间:2024/05/22 03:21
最长公共子序列(LCS)是一个很经典的问题。 给2个字符串s1,s2,求LCS(s1,s2). 用d[i][j]]表示s1[1-i]和是s2[1-j]的LCS.
if(s1[i]==s2[j]) d[i][j]=d[i-1][j-1]+1
else d[i][j]=max(d[i-1][j],d[I][j-1]).
这是一个1D/1D的动态规划问题,复查度为O(n*n)。 考虑如下特殊的LCS问题.求2个全排列p1,p2的LCS。
这个问题的特殊性在于,每个数只出现一次。我们观察转移方程,只有在是p1[i]==p2[j] 的时候才会出现+1的转移。那么其实有
我们用pari[i]表示s1[i]在s2[i]中出现的位置。 可以得出d[i][pari[i]]=max{d[l'][j']}+1 .i>l;.pari[i]>j'。这样可以用一个数据结构在维护,复杂度可以降低到nlogn级别
例1:
uva10635
#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <string>#include <cctype>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int inf = 0x3fffffff;const int mmax = 250*250+10;map<int,int>q;int p1[mmax],p2[mmax];int pos[mmax];int C[mmax];int n;int low_bit(int x){ return x&(-x);}void update(int pos,int val){ for(int i=pos;i<=n;i+=low_bit(i)) C[i]=max(C[i],val);}int get_max(int x){ int ans=0; for(int i=x;i>0;i-=low_bit(i)) ans=max(ans,C[i]); return ans;}int main(){ int t,ca=0; cin>>t; while(t--) { int d,l1,l2; q.clear(); scanf("%d %d %d",&d,&l1,&l2); l1++,l2++; for(int i=1;i<=l1;i++) scanf("%d",&p1[i]); for(int i=1;i<=l2;i++) { scanf("%d",&p2[i]); q[p2[i]]=i; } memset(C,0,sizeof C); n=l2; int ans=0; for(int i=1;i<=l1;i++) { if(!q.count(p1[i])) continue; int y=q[p1[i]]; int tmp=get_max(y)+1; ans=max(ans,tmp); update(y,tmp); } printf("Case %d: %d\n",++ca,ans); } return 0;}
这题还有一种特别的解法,用映射的手段,吧s1的映射成,1,2,3,4.。。。n,求s2 的最长上升序列。用n*logn的算法
#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <string>#include <cctype>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int inf = 0x3fffffff;const int mmax = 250*250+10;int p1[mmax],p2[mmax];int dp[mmax];map<int,int>q;int main(){ int t,ca=0; cin>>t; while(t--) { int d,l1,l2; q.clear(); scanf("%d %d %d",&d,&l1,&l2); l1++,l2++; for(int i=1;i<=l1;i++) { scanf("%d",&p1[i]); q[p1[i]]=i; } for(int i=1;i<=l2;i++) { int x; scanf("%d",&x); if(!q.count(x)) p2[i]=0; else p2[i]=q[x]; } int len=1; dp[1]=p2[1]; for(int i=2;i<=l2;i++) { int l=1,r=len+1; int mid=(l+1)>>1; while(l<r) { mid=(l+r)>>1; if(dp[mid]<p2[i]) l=mid+1; else r=mid; } dp[r]=p2[i]; if(r==len+1) len++; } printf("Case %d: %d\n",++ca,len); } return 0;}
解法自行YY,给出AC代码
#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <string>#include <cctype>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int inf = 0x3fffffff;const int mmax =100010;map<int,int>q;int p1[mmax],p2[mmax];int next[mmax];int C[mmax];int n;int low_bit(int x){ return x&(-x);}void update(int pos,int val){ for(int i=pos;i<=n;i+=low_bit(i)) C[i]=max(C[i],val);}int get_max(int x){ int ans=0; for(int i=x;i>0;i-=low_bit(i)) ans=max(ans,C[i]); return ans;}int main(){ while(cin>>n) { n*=5; q.clear(); for(int i=1;i<=n;i++) scanf("%d",&p1[i]); memset(next,-1,sizeof next); for(int i=1;i<=n;i++) { scanf("%d",&p2[i]); if(!q.count(p2[i])) q[p2[i]]=i; else { next[i]=q[p2[i]]; q[p2[i]]=i; } } memset(C,0,sizeof C); int ans=0; for(int i=1;i<=n;i++) { if(!q.count(p1[i])) continue; int y=q[p1[i]]; while(y+1) { int tmp=get_max(y-1)+1; ans=max(ans,tmp); update(y,tmp); y=next[y]; } } printf("%d\n",ans); } return 0;}
0 0
- 最长公共子序列的另一类优化方法
- 最长公共子序列 空间优化最长公共子序列
- 最长的公共子序列
- 求最长公共子序列的空间优化。
- 关于最长公共子序列问题的空间优化
- 最长公共上升子序列的DP解法及其优化
- 最长公共上升子序列的DP解法及其优化
- 最长公共上升子序列的DP解法及其优化
- 最长公共子序列空间优化算法
- 两个序列的最长公共子序列
- 最长公共子序列
- 最长公共子序列
- 最长公共子序列
- 最长公共子序列
- 最长公共子序列...
- 最长公共子序列
- 最长公共子序列
- 最长公共子序列
- cocoapods工程路径变更后library not found解决方案
- Android 音频焦点(Audio Focus)
- 黑马程序员-------java语法基础
- python单线程网络爬虫
- python 爬虫抓取奥数题
- 最长公共子序列的另一类优化方法
- 高端LED显示屏为何青睐黑灯?
- 排序1-冒泡,选择和插入
- 音频焦点 (audio focus)(二)
- Javascript之创建对象(工厂模式与构造函数模式)
- 单片机的独立键盘
- 集群
- c++_1st par
- Codeforces 553B Kyoya and Permutation