【mark】最長公共子序列(poj 1458+hdu 1159)
經典的問題,在各大部落格上有數不清的好帖子
下面為最常見的n^2演算法
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> using namespace std; int f[500][500]; char x[500],y[500]; int solve(int a,int b) { int i,j; memset(f,0,sizeof(f)); for(i=1;i<=a;i++) { for(j=1;j<=b;j++) { if(x[i]==y[j]) { f[i][j]=f[i-1][j-1]+1; } else f[i][j]=max(f[i-1][j],f[i][j-1]); } } return f[a][b]; } int main() { int a,b; while(scanf("%s",&x[1])!=EOF) { scanf("%s",&y[1]); a=strlen(&x[1]); b=strlen(&y[1]); printf("%d\n",solve(a,b)); } return 0; }
O(nlogn):
最長公共子序列(LCS)最常見的演算法是時間複雜度為O(n^2)的動態規劃(DP)演算法,但在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) 獲取最長公共子序列
效能分析:
(1) 排序複雜度為nlogn
(2) 獲取一個元素在B中的序號的複雜度,最小為logn,最大為n,獲取所有元素的複雜度為 nlogn === n*n
(3) LIS 複雜度為nlogn
因此總體複雜度在nlogn 到 n*n logn之間,但如果(2) 步驟中A中元素在B中的序號對數很少時,效能相當優越,在實際測試時,string 中均為小寫字母,長度為10000的情況下,這種方法比普通的LCS快一倍以上;如果string 中的字元擴充套件成char,即0-255,則這種方法比普通的LCS快至少一個數量級。以下為程式碼實現,可以參考:
附個參考程式碼:
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <iostream>
- #include <string>
- #include <math.h>
- #include <vector>
- #include <queue>
- #include <algorithm>
- using namespace std;
- const int maxn = 1501 ;
- vector<int> location[26] ;
- int c[maxn*maxn] , d[maxn*maxn] ;
- inline int get_max(int a,int b) { return a > b ? a : b ; }
- //nlogn 求lcs
- int lcs(char a[],char b[])
- {
- int i , j , k , w , ans , l , r , mid ;
- for( i = 0 ; i < 26 ; i++) location[i].clear() ;
- for( i = strlen(b)-1 ; i >= 0 ; i--) location[b[i]-'a'].push_back(i) ;
- for( i = k = 0 ; a[i] ; i++)
- {
- for( j = 0 ; j < location[w=a[i]-'a'].size() ; j++,k++) c[k] = location[w][j] ;
- }
- d[1] = c[0] ; d[0] = -1 ;
- for( i = ans = 1 ; i < k ; i++)
- {
- l = 0 ; r = ans ;
- while( l <= r )
- {
- mid = ( l + r ) >> 1 ;
- if( d[mid] >= c[i] ) r = mid - 1 ;
- else l = mid + 1 ;
- }
- if( r == ans ) ans++,d[r+1] = c[i] ;
- else if( d[r+1] > c[i] ) d[r+1] = c[i] ;
- }
- return ans ;
- }
- int main()
- {
- char a[maxn] , b[maxn] ;
- while (~scanf("%s%s",a,b))
- {
- printf("%d/n",lcs(a,b));
- }
- }
本文出自 “[email protected]” 部落格,請務必保留此出處http://karsbin.blog.51cto.com/1156716/966387
相關題目:
POJ1458
POJ2250
POJ1159
基本的最長公共子序列
POJ2533
最長不減(不增)子序列,用方法1、2即可
WOJ1398
最長不減(不增)子序列,方法1、2超時
相關推薦
【mark】最長公共子序列(poj 1458+hdu 1159)
經典的問題,在各大部落格上有數不清的好帖子 下面為最常見的n^2演算法 #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #inclu
【DP】最長公共子序列
amp 給定 scrip ros script print 最長 去掉 != Description 字符序列的子序列是指從給定字符序列中隨意地(不一定連續)去掉若幹個字符(可能一個也不去掉)後所形成的字符序列。令給定的字符序列X=“x0,x1,…,xm-1”,序列Y
洛谷 P1439 【模板】最長公共子序列
clu () 休閑 一句話 中一 AD DC == c++ 神TM模板。。我本來想休閑一下寫點水題的。。。 開始做的時候直接敲了一個O(N2)的算法上去,編譯的時候才發現根本開不下。。 好了,談回這道題。 先不加證明的給出一種算法。 若有一組數據 2 4 2 5 1 3
luogu P1439 【模板】最長公共子序列
bsp 第一個 順序 它的 amp while ++ return scan 題目qwq (第一道藍題) 據說是用了hash的思想(?) 總之是先把第一個序列每個數出現的順序記下來(其實第一個序列的數字不用記), 然後第二個序列的每個數都對照它的順序,這樣只要得到一個升序的
P1439 【模板】最長公共子序列
題目描述 給出1-n的兩個排列P1和P2,求它們的最長公共子序列。 輸入輸出格式 輸入格式: 第一行是一個數n, 接下來兩行,每行為n個數,為自然數1-n的一個排列。 輸出格式: 一個數,即最長公共子序列的長度 輸入輸出樣例 輸入樣例#1: 複製 5 3 2 1 4 5 1 2 3 4 5
洛谷P1439 【模板】最長公共子序列
1-n ont range else 輸入輸出格式 pac algo mes 格式 題目描述 給出1-n的兩個排列P1和P2,求它們的最長公共子序列。 輸入輸出格式 輸入格式: 第一行是一個數n, 接下來兩行,每行為n個數,為自然數1-n的一個排列。 輸出格式:
【模板】最長公共子序列(LCS)。
ons 理解 思路 esp 自動 const () -- bing 看過好多人的博客,感覺要麽是太復雜要麽就是太不容易理解。 那就親自動手寫一個通俗易懂的。 先定義兩個數組,第一個數組為主,用第二個數組來匹配第一個,看能有多少可以對應上的。 所以,其實第一個數組的內容可以暫
【模板】最長公共子序列
#include <stdio.h> #include <string.h> #include <algorithm> using namespace
[題解]洛谷P1439 【模板】最長公共子序列
序列 printf %d span pac namespace int turn esp 原題 原題 思路 將第一個序列依次從左到右標號,然後映射到第二個序列中 因為第一個序列標號只上升的所以問題就轉化為序列2標號後的最長上升子序列 代碼 #include&
洛谷 P1439 【模板】最長公共子序列 題解
inf bubuko return https == span ++ 每一個 upper 題目傳送門 看起來是一道十分經典的LCS問題 很容易想到 n2 的一般算法:主題代碼如下: for (int i = 1; i <= n; i++) fo
【bzoj5427】最長上升子序列(貪心+LIS)
貪心 去掉 ati lse com set event color tps 題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=5427 因為noip,博客咕了好久,這幾天集中填一下坑。 這題我們可以
NYOJ題目36-最長公共子序列(經典動態規劃題)
最長公共子序列 時間限制:3000 ms | 記憶體限制:65535 KB 難度:3 描述咱們就不拐彎抹角了,如題,需要你做的就是寫一個程式,得出最長公共子序列。 tip:最長公共子序
【動態規劃】最長公共子序列問題
clas == 搜索 ios for 參考 pan 公式 是否 題目描述: 給定兩個字符串s1s2……sn和t1t2……tn。求出這兩個字符串最長的公共子序列的長度。字符串s1s2……sn的子序列指可以表示為si1si2……sim(i1<i2<……<im)
【例9.9】最長公共子序列
std 不存在 cst i++ 公共子串 ostream ont enter http 【例9.9】最長公共子序列 鏈接:http://ybt.ssoier.cn:8088/problem_show.php?pid=1265 時間限制: 1000 ms 內
【NOJ1041】【DP_動態規劃】最長公共子序列
1041.最長公共子序列 時限:1000ms 記憶體限制:200000K 總時限:3000ms 描述 一個給定序列的子序列是在該序列中刪去若干元素後得到的序列。確切地說,若給定序列X=<x1, x2,…, xm>,則另一序列Z=<z1, z2,
【LeetCode】Longest Common Subsequence最長公共子序列(求出某一解+LCS長度)
Longest Common Subsequence 給出兩個字串,找到最長公共子序列(LCS),返回LCS的長度。 說明 最長公共子序列的定義: • 最長公共子序列問題是在一組序列(通常2個)中找到最長公共子序列(注意:不同於子串,LCS不需要是
【經典動態規劃問題】最長公共子序列LCS
目錄 題目 題目分析 狀態 邊界值討論 其他情況討論 程式碼實現 從題目出發分析如何用動態規劃求解最長公共子序列問題 題目 給定兩個字串A和B,返回兩個字串的最長公共子序列的長度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”1234
【動態規劃】最長公共子序列與最長公共子串
1. 問題描述 子串應該比較好理解,至於什麼是子序列,這裡給出一個例子:有兩個母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs與belong中都出現過並且出現順序與母串保持一致,我們將其稱為公共子序列。最長公共子序列(Longest Common Subsequence
【水:最長公共子序列】【HDU1159】【Common Subsequence】
Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 24919 Acc
【演算法】動態規劃法——最長公共子序列(LCS)
前言 這篇是自己寫的第一篇關於演算法方面的部落格,寫他是因為自己今天開啟筆記,剛好看到了它,就這麼簡單。 這篇部落格主要想講講動態規劃法,然後以LCS問題為例展開來說一下怎麼利用動態規劃法求解它,下面是自己的一些理解和總結,有不對的地方還請大家指正。動