動態規划1--最長公共子序列
一、動態規划
經常會遇到復雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題。簡單地采用把大問題分解成子問題,並
綜合子問題的解導出大問題的解的方法,問題求解耗時會按問題規模呈冪級數增加。
為了節約重復求相同子問題的時間,引入一個數組,不管它們是否對最終解有用,把所有子問題的解存於該數組中,這就
是動態規划法所采用的基本方法。
二、心得
遞推公式的推導
遞推公式的證明方法
代碼的寫法:把遞推公式直接寫進代碼即可
三、題目
給出兩個字符串,求出這樣的一個最長的公共子序列的長度:子序列中的每個字符都能在兩個原串中找到,而且每個字符的先后順序和原串中的先后順序一致。
Sample Input:樣例輸入
abcfbc abfcab
programming contest
abcd mnp
Sample Output:樣例輸出
4
2
0
四、分析
2、證明
S1[i-1]!= s2[j-1]時,MaxLen(S1,S2)不會比MaxLen(S1,S2j-1)
和MaxLen(S1i-1,S2)兩者之中任何一個小,也不會比兩者都大。
(1)不比任何一個小:MaxLen(S1,S2)字符串長於后兩者
(2)也不會比兩者都大:反證法,假設比兩者都大:
若MaxLen(S1,S2)比MaxLen(S1,S2j-1)大,說明S2(j)這個字符與S1中的字符相等,並且S2(j)和這個相等的字符是最長公共子序列的最后一個。
若MaxLen(S1,S2)比MaxLen(S1i-1,S2)大,說明S1(i)這個字符與S2中的字符相等,並且S1(i)和這個相等的字符是最長公共子序列的最后一個。
上面兩種情況都是最長公共子序列的最后一個,而這個最長公共子序列是MaxLen(S1,S2)的最長公共子序列,所以最后一個要相等。
那會得出S1[i]== s2[j]的結論,與假設沖突。
五、代碼及結果
1 /* 2 最長公共子序列 3 1、遞推公式: 4 (分最后一個相同和最后一個不同來分析) 5 當i或j等於0,MaxLen(i,j)==0; 6 當s1和s2的最后一個字符相同時,MaxLen(i,j)=MaxLen(i-1,j-1)+1; 7 當s1和s2的最后一個字符不同時,MaxLen(i,j) = Max(MaxLen(i,j-1),MaxLen(i-1,j) ); 8 2、證明 9 S1[i-1]!= s2[j-1]時,MaxLen(S1,S2)不會比MaxLen(S1,S2j-1) 10 和MaxLen(S1i-1,S2)兩者之中任何一個小,也不會比兩者都大。 11 (1)不比任何一個小:MaxLen(S1,S2)字符串長於后兩者 12 (2)也不會比兩者都大:反證法,假設比兩者都大,那會得出S1[i-1]== s2[j-1]的結論,與假設沖突 13 3、代碼 14 直接寫遞推公式就好了 15 */ 16 /* 17 錯誤一:結果不對 18 for(j=1;j<=length2;j++),漏了等號,所以都沒執行到這來,所以結果不對 19 */ 20 #include <iostream> 21 #include <cstring> 22 using namespace std; 23 char sz1[1000];//字符數組1 24 char sz2[1000];//字符數組2 25 int maxLen[1000][1000]; 26 //MaxLen(i,j)表示s1的左邊i個字符形成的子串, 27 //與s2左邊的j個字符形成的子串的最長公共子序列的長度(i,j從0開始算) 28 int main(){ 29 freopen("in.txt","r",stdin); 30 while(cin>>sz1>>sz2){ 31 int length1=strlen(sz1);//求字符數組1的長度 32 int length2=strlen(sz2);//求字符數組2的長度 33 int nTmp; 34 int i,j; 35 //初始化邊界情況 36 for(i=0;i<=length1;i++) 37 maxLen[i][0]=0; 38 for(j=0;j<=length2;j++) 39 maxLen[0][j]=0; 40 //動態規划求解最長公共子序列 41 for(i=1;i<=length1;i++){ 42 for(j=1;j<=length2;j++){ 43 if(sz1[i-1]==sz2[j-1]){//字符數組從0開始存數據的 44 //當s1和s2的最后一個字符相同時,MaxLen(i,j)=MaxLen(i-1,j-1)+1; 45 maxLen[i][j]=maxLen[i-1][j-1]+1; 46 } 47 else{ 48 //當s1和s2的最后一個字符不同時,MaxLen(i,j) = Max(MaxLen(i,j-1),MaxLen(i-1,j) ); 49 maxLen[i][j]=max(maxLen[i][j-1],maxLen[i-1][j]); 50 } 51 } 52 53 } 54 /* 55 for(i=1;i<=length1;i++){ 56 for(j=1;j<=length2;j++){ 57 cout<<maxLen[i][j]<<" "; 58 } 59 cout<<endl; 60 } 61 */ 62 //cout<<length1<<" "<<length2<<endl; 63 cout<<maxLen[length1][length2]<<endl; 64 } 65 return 0; 66 }