動態規劃 找出所有的LCS

2021-05-21 23:49:55 字數 4618 閱讀 8470

用動態規劃法

求解問題特性:

a.具有重疊性

;b.具有最優子結構性質 1.

最長公共子串行

(lcs)

的概念: 若z

則稱z是x和y 的最長公共子串行,記為z

îlcs(x , y)。

最長公共子串行往往不止乙個。

e.g. x=,  y=, 則

z=,   z』=,  z』』=

均屬於lcs(x , y) ,即x,y有3個lcs。

2.尋找最長公共子串行

由書上分析結果:

(1)若xm=y

n,則問題化歸成求x

m-1與y

n-1的lcs

(lcs(x , y)的長度等於lcs(x

m-1, y

n-1)的長度加1) (

2)若xm

≠yn則問題化歸成求x

m-1與y的lcs及x與y

n-1的lcs

lcs(x , y)的長度為:

max3.求取最長公共子串行

引進乙個二維陣列c,用c[i,j]記錄xi與y

j的lcs的長度

如果我們是自底向上進行遞推計算,那麼在計算c[i,j]之前,

c[i-1,j-1], c[i-1,j]與c[i,j-1]均已計算出來。此時我們

根據x[i]=y[j]還是x[i]

¹y[j],就可以計算出c[i,j]:

若x[i]=y[j],則執行c[i,j]←c[i-1,j-1]+1;若x[i]

¹y[j],則根據:

c[i-1,j]≥c[i,j-1],則c[i,j]取c[i-1,j];否則c[i,j]取c[i,j-1]。即有

c[i,j]=

e.g. 如下圖:

0  1  

2  3 

4 5  6

yj b d 

c a 

b  a

0  x

i0  

0  0 

0  0 

0  0 ←↑

↑←↑↖↖

1  a 0 ←

0 ←0←

0  1

←1  1

↖↑↖

2  b 

0 1 ←1

←1 ←1 

2 ←2

↑←↑↖←↑

←↑ 3  c 

0 1 ←1 

2 ←2←2 

←2 ↖ 

←↑↑←↑↖

4  b 

0  1 

←1  2 ←

2 3 ←3 

↑↖←↑

←↑↑←↑

5  d  

0  1 2←

2 ←2  3 ←3

↑↑←↑

↖←↑↖

6  a  

0  1  2←

2  3

←3  4

↖↑←↑↑

↖←↑7  b  0 

1  2

←2  

3 4 ←4

為了搜尋到所有的lcs的

,使用乙個m

´n的二維陣列b,

b[i,j]記錄c[i,j]是通過哪乙個子問題的值求得的,

以決定搜尋的方向:

若c[i-1,j]

>

c[i,j-1],則b[i,j]中記入「↑」; 若

c[i-1,j]=c[i,j-1]時,

則b[i,j]

中記入「←↑」,

若c[i-1,j]

執行的搜尋方向:

x[i]=y[j]要執行b[i,j]=「↖」,

x[i]

¹y[j]且c[i,j-1] > c[i-1,j]要執行b[i,j]=「←」,

x[i]

¹y[j]且c[i,j-1] 

x[i]

¹y[j]且c[i,j-1] = c[i-1,j] 要執行b[i,j]=「←↑」,

演算法 lcs_l(x,y,m,n,c)

for i=0 to m do c[i,0]←0

for j=1 to n do c[0,j]←0

for i=1 to m do 

}else if c[i-1,j]

>

c[i,j-1] 

then 

else if c[i-1,j]

=c[i,j-1] 

then 

}else 

演算法的時間複雜度顯然是

q(m×n)的。

4 程式如下:

// 輸出lcs.cpp 

#include

#include

#include

#include

#include

#include

using namespace std;

//*******************************尋找最長公共子串行***********************//

void  lcs_l(int x,int y,int m,int n,int c[10],char d[10])

//i=0時取值為0

for(j=0;j<=n;j++)

//j=0時取值為0

for(i=1;i<=m;i++)                          //獲取c[i][j]的值

else

else if(c[i-1][j]==c[i][j-1])

else

} }

} cout<

for(k=0;k<=10;k++)     //輸出二維陣列b

//呼叫顯示最長公共子串行函式

} //***********************輸出乙個最長公共子串行**********************//

void lcs_outputone(int c[10],int x,int y,int i,int j)

//到邊界是返回

if(x[i-1]==y[j-1])            //b[i][j]=='$'

else

if(c[i-1][j]>c[i][j-1])

lcs_outputone(c,x,y,i-1,j);   // b[i][j]=='>'

else  if(c[i-1][j]

lcs_outputone(c,x,y,i,j-1);

//b[i][j]='

else

lcs_outputone(c,x,y,i,j-1);      //b[i][j]='=' }

//***********************輸出所有最長公共子串行**********************//

void lcs_outputall(int c[10],char d[10],int x,int i,int j,int result,int len,int k)

cout<

return; }

else

else

else if(d[i][j]=='

else

} }

} //***************************主函式********************************//

int main() ;

int b[9]=;

int c[11][10]=;

char d[11][10]=;

system("color fc");

srand(time(0));

cout<

for(i=0;i<10;i++)//

cout<

for(j=0;j<9;j++)//

lcs_l(a,b,10,9,c,d);//

cout<

for(i=0;i<11;i++)      //顯示二維陣列c

len=c[i-1][j-1];//

x=10;

y=9;

k=len;

int result[len];

cout<

lcs_outputone(c,a,b,x,y);

cout<

cout<

lcs_outputall(c,d,a,x,y,result,len,k);

cout<

return 0; }

5.結果分析:

由lcs_output_all函式可知,求出所有的lcs

的長度就是根據陣列b[i][j]中的值,即搜尋的方向資訊來遍歷所有可能的路徑找到滿足條件的元素集合。函式lcs_l的時間複雜度是求解陣列b和c的執行時間,是o(mn+m+n)。而函式lcs_output_all的時間複雜度取決於遍歷的路徑數。在最好的情況下,即x序列和y序列完全相等,m=n,陣列b中的值都是『$

』(指向對角線方向),所以時間複雜度是o(m)。而在最壞情況下,即x序列和y序列不存在公共子串行,陣列b中的值都是「4」,就是要分別沿向上和向左的方向搜尋,這是每處理一次x[i]和y[j],都必須沿著兩個方向呼叫函式lcs_output_all,當遇到i=0或j=0的情況開始返回,只有在搜尋完所有的路徑後演算法才結束。要確定最壞情況的時間複雜度,就是要計算出從點(m,n)到i=0或j=0(除(i,j)=(0,0)外)的所有路徑。

LCS問題 動態規劃

簡述 lcs問題,即最長公共子串行問題,給定兩個序列x 和y 求x y最長的公共子串行。與lis類似,lcs也是可以不連續的。解題思路 本人覺得在這個問題上演算法導論講的很好,所以在此我主要是整理。1 首先我們來考慮暴力搜尋求解的方法,我們要暴力列舉x的所有子串行,然後再看看是不是也是y的子串行,這...

動態規劃 LCS計算

int findlcs string a,int n,string b,int m dp的第一行 for int j 0 j m 1 j 其他位置的dp值 for int i 1 i n 1 i else dp i j dp i 1 j dp i j 1 dp i 1 j dp i j 1 retu...

動態規劃解LCS問題

今天研究了一下動態規劃,思想很簡單 循序漸進,區域性推到整體。但運用起來還是不太好想的。下面用動態規劃解lcs最大公共子串問題 寫了兩個函式lcs和lcs inhance,前者用矩陣實現 用於理解原理 後者用兩個陣列實現 節省空間 如下 include includeusing namespace ...