最长公共子序列(动态规划)
动态申请二维数组:
int row; //行 int col; //列 cin >> row >> col; //动态申请二维数组 int** p = new int* [row]; for (int i = 0; i < row; i++) { p[i] = new int[col]; } //释放二维数组所占用的空间 for (int i = 0; i < row; i++) { delete[] p[i]; } delete[] p;
LCS问题即最长公共子序列问题,它不要求所求得的字符在所给的字符串中是连续的(例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子序列,则输出它们的长度4,并打印任意一个子序列)
最长公共子序列的结构有如下表示:
设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:
1、若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
2、若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;
3、若xm≠yn且zk≠yn ,则Z是X和Yn-1的最长公共子序列。
其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。
动态转换方程:
由算法LCS_LENGTH计算得到的数组b可用于快速构造序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列。首先从b[m,n]开始,沿着其中的箭头所指的方向在数组b中搜索。
当b[i,j]中遇到"↖"时(意味着xi=yi是LCS的一个元素),表示Xi与Yj的最长公共子序列是由Xi-1与Yj-1的最长公共子序列在尾部加上xi得到的子序列;
当b[i,j]中遇到"↑"时,表示Xi与Yj的最长公共子序列和Xi-1与Yj的最长公共子序列相同;
当b[i,j]中遇到"←"时,表示Xi与Yj的最长公共子序列和Xi与Yj-1的最长公共子序列相同。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 //#include<bits/stdc++.h> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<cstdio> 7 #include<malloc.h> 8 #include<sstream> 9 #include<string.h> 10 using namespace std; 11 12 typedef long long ll; 13 14 bool cmp(int a, int b) { 15 return a > b; 16 } 17 18 void OutPutLCS(int** B, string s1, int s1len, int s2len); 19 20 int main() { 21 string s1, s2; 22 cin >> s1 >> s2; 23 int s1len = s1.length(); 24 int s2len = s2.length(); 25 26 //动态申请二维数组 27 int** B = new int* [s1len + 1]; 28 for (int i = 0; i <= s1len; i++) { 29 B[i] = new int[s2len + 1]; 30 } 31 int** C = new int* [s1len + 1]; //记录最优解值的表 32 for (int i = 0; i <= s1len; i++) { 33 C[i] = new int[s2len + 1]; 34 } 35 36 for (int i = 0; i <= s1len; i++) { 37 C[i][0] = 0; 38 B[i][0] = -2; //-2表示没有方向 39 } 40 for (int i = 0; i <= s2len; i++) { 41 C[0][i] = 0; 42 B[0][i] = -2; //-2表示没有方向 43 } 44 for (int i = 1; i <= s1len; i++) { 45 for (int j = 1; j <= s2len; j++) { 46 if (s1[i - 1] == s2[j - 1]) { 47 C[i][j] = C[i - 1][j - 1] + 1; 48 B[i][j] = 0; //0表示斜左上 49 } 50 else { 51 if (C[i - 1][j] >= C[i][j - 1]) { 52 C[i][j] = C[i - 1][j]; 53 B[i][j] = -1; //-1表示竖直向上 54 } 55 else { 56 C[i][j] = C[i][j - 1]; 57 B[i][j] = 1; //1表示横向左 58 } 59 } 60 } 61 } 62 for (int i = 0; i <= s1len; i++) { 63 for (int j = 0; j <= s2len; j++) { 64 cout << C[i][j] << " "; 65 } 66 cout << endl; 67 } 68 cout << endl; 69 for (int i = 0; i <= s1len; i++) { 70 for (int j = 0; j <= s2len; j++) { 71 printf("%2d ", B[i][j]); 72 } 73 cout << endl; 74 } 75 OutPutLCS(B, s1, s1len, s2len); 76 return 0; 77 } 78 79 void OutPutLCS(int** B, string s1, int s1len, int s2len) { 80 if (s1len == 0 || s2len == 0) 81 return; 82 if (B[s1len][s2len] == 0) //斜左向上 83 { 84 OutPutLCS(B, s1, s1len - 1, s2len - 1); 85 cout << s1[s1len - 1]; 86 } 87 else if (B[s1len][s2len] == -1) { //竖直向上 88 OutPutLCS(B, s1, s1len - 1, s2len); 89 } 90 else 91 OutPutLCS(B, s1, s1len, s2len - 1); //横向左 92 }
最长公共子序列
时间限制:3000 ms | 内存限制:65535 KB
难度:3
- 描述
- 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列。
tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。
- 输入
- 第一行给出一个整数N(0<N<100)表示待测数据组数
接下来每组数据两行,分别为待测的两组字符串。每个字符串长度不大于1000. - 输出
- 每组测试数据输出一个整数,表示最长公共子序列长度。每组结果占一行。
- 样例输入
-
2 asdf adfsd 123abc abc123abc
- 样例输出
-
3 6
#include<iostream> #include<cstdio> #include<cstring> using namespace std; char str1[1005],str2[1005],a[1005],b[1005]; int dp[1005][1005]; int main(){ int n; cin>>n; while( n-- ){ cin>>a; cin>>b; int len1 = strlen(a); int len2 = strlen(b); int i,j; dp[0][0] = 0; for( i = 0; i < len1; i++ ) str1[i+1] = a[i]; for( i = 0; i < len2; i++ ) str2[i+1] = b[i]; for( i = 1; i <= len1; i++ ) for( j = 1; j <= len2; j++ ){ if( str1[i] == str2[j] ) dp[i][j] = dp[i-1][j-1]+1; else dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } cout<<dp[len1][len2]<<endl; } return 0; }