nyist oj 36 最長公用子序列 (動態規劃基礎題),nyistoj
最長公用子序列時間限制:3000 ms | 記憶體限制:65535 KB難度:3
-
描述
-
咱們就不拐彎抹角了,如題,需要你做的就是寫一個程式,得出最長公用子序列。
tip:最長公用子序列也稱作最長公用子串(不要求連續),英文縮寫為LCS(Longest Common Subsequence)。其定義是,一個序列 S ,如果分別是兩個或多個已知序列的子序列,且是所有符合此條件序列中最長的,則 S 稱為已知序列的最長公用子序列。
-
輸入
-
第一行給出一個整數N(0<N<100)表示待測資料群組數
接下來每組資料兩行,分別為待測的兩組字串。每個字串長度不大於1000.
-
輸出
-
每組測試資料輸出一個整數,表示最長公用子序列長度。每組結果佔一行。
-
範例輸入
-
2asdfadfsd123abcabc123abc
-
範例輸出
-
36
-
來源
-
經典
-
上傳者
hzyqazasdf
開始要刷動態規劃的題啦;從入門題練練手,http://blog.csdn.net/v_july_v/article/details/6695482 (關於演算法的講解)參考了大神的部落格,看了對這個內容有了那麼一點點瞭解了吧,直接用這個題目練練手。主要要掌握動態規劃的這種思想!
動態規劃思想,主要是遞推公式,求最佳化問題,保證當時位置是最優,分治的思想;
這個題目的思路就是,從最後一個字元開始,如果兩個字串的最後一個字元相等,說明最後一個字元,在最長的公用序列裡面,最長公用序列的前一個,肯定也是兩個字串的最長公用子序列,遞推公式就是 dp[i][j]=dp[i-1][j-1]+1;
其他情況,如果不相等就是 dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
第一次水過的代碼;
#include <cstdio>#include <cstring>#define max(a, b) a > b ? a : busing namespace std;const int maxn=1001;int dp[maxn][maxn];//儲存當前位置最長公用子序列的個數char s1[maxn],s2[maxn];int main(){ int n; int len1,len2; scanf("%d",&n); getchar(); while(n--) { memset(dp,0,sizeof(dp)); scanf("%s%s",s1,s2); len1=strlen(s1); len2=strlen(s2); for(int i=1;i<=len1;i++) for(int j=1;j<=len2;j++) { if(s1[i-1]==s2[j-1])//先前這個地方寫成s1[i]==s2[j]就一直wa 不知道為什麼,範例都能過 dp[i][j]=dp[i-1][j-1]+1; else dp[i][j] = max(dp[i][j-1], dp[i-1][j]); } printf("%d\n",dp[len1][len2]); } return 0;}
看到別人可以直接用一維數組來做,進行了記憶體上的最佳化;值得學習一下;
#include <stdio.h>#include <string.h>char s1[1001], s2[1001];int dp[1001], t, old, tmp;int main(){ scanf("%d", &t); getchar(); while(t--){ gets(s1); gets(s2); memset(dp, 0, sizeof(dp)); int lenS1=strlen(s1), lenS2=strlen(s2); for(int i=0; i<lenS1; i++){ old=0; //若s1[i]==s2[j], dp[i][j] = dp[i-1][j-1]+1 //否則,dp[i][j] = max(dp[i-1][j], dp[i][j-1]) //此處進行了空間最佳化,old 代表 dp[i-1][j-1] //dp[j-1] 代表 dp[i][j-1], dp[j] 代表 dp[i-1][j] for(int j=0; j<lenS2; j++){ tmp = dp[j]; if(s1[i]==s2[j]) dp[j] = old+1; else if(dp[j-1]>dp[j])dp[j]=dp[j-1]; old = tmp; } } printf("%d\n", dp[lenS2-1]); } return 0;}
找出(A,D,C,B,B,C,B)與(D,D,C,B,A,C)最長公用子序列,並給出構造過程
動態規劃
if(a[i]==b[j])
d[i][j]=d[i-1][j-1]+1
else
d[i][j]=max(d[i-1][j],d[i][j-1])
初始化
d[i][0]=0;
d[0][j]=0;
為節省空間的,可以用滾動數組 d只設定兩行就可以
動態規劃的問題:最長公用子序列代碼如下,為何當輸入兩個字串分別為“123456”以及“as”時輸出
main()前面不該有int,其次for迴圈裡如果迴圈變數是從0下表開始的,就該是小於strlen1和小於strlen2,沒有等於