最長公共子序列,顧名思義就是找出兩個序列的最長的 共同的 子序列,像是abc、bac的公共子序列可以是a、b、c、ac、bc,最長的公共子序列長度為2。
那我們要怎麼求出最長的公共子序列的長度,我們可以建立一個二維陣列來運算(lcs[m][n]:m為第一個序列的長度、n為第二個序列的長度)。在判斷的時候會有兩種情況,兩個東西相同或不相同。
如果相同的話,我們的lcs[i][j] = lcs[i-1][j-1] + 1。
如果相異的話,我們的lcs[i][j] = max(lcs[i-1][j], lcs[i][j-1])。
以下舉abc,bac為例:

這題就是標準的最長公共子序列,只不過比的是int。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include<bits/stdc++.h> #define speedup ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) using namespace std;
int a[100],b[100];
int lcs(int n,int m){ int i,j,map[n][m]; map[0][0] = (a[0] == b[0] ? 1 : 0);
for(i=1;i<m;i++){ map[0][i] = (a[0] == b[i] ? 1 : map[0][i-1]); }
for(i=1;i<n;i++){ map[i][0] = (a[i] == b[0] ? 1 : map[i-1][0]); }
for(i=1;i<n;i++){ for(j=1;j<m;j++){ if(a[i] == b[j]){ map[i][j] = map[i-1][j-1] + 1; } else{ map[i][j] = max(map[i-1][j], map[i][j-1]); } } }
return map[n-1][m-1]; }
int main(){ speedup; int m,n,i,cnt=1; while(cin >> n >> m){ if(n==0 && m==0){break;} for(i=0;i<n;i++){cin >> a[i];} for(i=0;i<m;i++){cin >> b[i];} cout << "Twin Towers #" << cnt++ << "\nNumber of Tiles : " << lcs(n,m) << "\n\n"; } return 0; }
|
這題也是標準的最長公共子序列,甚至比上一題還標準。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include<stdio.h> #include<string.h> #define max(a,b) a>b?a:b
char a[1001],b[1001];
int lcs(int n,int m){ int i,j,map[n][m]; map[0][0] = (a[0] == b[0] ? 1 : 0);
for(i=1;i<m;i++){ map[0][i] = (a[0] == b[i] ? 1 : map[0][i-1]); }
for(i=1;i<n;i++){ map[i][0] = (a[i] == b[0] ? 1 : map[i-1][0]); }
for(i=1;i<n;i++){ for(j=1;j<m;j++){ if(a[i] == b[j]){ map[i][j] = map[i-1][j-1] + 1; } else{ map[i][j] = max(map[i-1][j], map[i][j-1]); } } }
return map[n-1][m-1]; }
int main(){ while(scanf("%s%s",a,b) != EOF){ int al = strlen(a); int bl = strlen(b); printf("%d\n",lcs(al,bl)); } return 0; }
|
封面圖源:Pixiv