题意
给出两段文字,求最长公共子序列。
思路
经典的最长公共子序列模型,有所不同的是这道题不是求最长公共子序列的长度,而是打印最长的公共子序列。所以在列出状态转移方程的基础上思考如何记录序列是很重要的。
C[i, j]表示第一个序列的前i个与第二个序列的前j个最长公共子序列的长度。
我采用的方法是用dir二维数组记录状态转移的方向,然后递归打印即可。
AC代码:
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <string>
#include <deque>
#include <queue>
#include <set>
#include <iostream>
#include <sstream>
#include <algorithm>
typedef long long LL;
using namespace std;
const int maxn = 100+10;
vector<string> v1;
vector<string> v2;
int dp[maxn][maxn];
int dir[maxn][maxn]; // 记录搜索方向
bool fir = true;
void printLCS(int i, int j) {
if (i == 0||j == 0) return;
if (dir[i][j] == 0) {
printLCS(i-1, j-1);
if (fir) {
cout << v1[i-1];
fir = false;
}
else cout << " " << v1[i-1];
}
else if (dir[i][j] == 1) printLCS(i-1, j);
else printLCS(i, j-1);
}
void init() {
fir = true;
v1.clear();
v2.clear();
}
int main() {
// freopen("input.txt", "r", stdin);
string s;
int len1, len2;
while(cin >> s) {
v1.push_back(s);
while (cin >> s) {
if (s == "#") break;
v1.push_back(s);
}
while (cin >> s) {
if (s == "#") break;
v2.push_back(s);
}
len1 = (int) v1.size();
len2 = (int) v2.size();
for (int i = 0; i <= len1; i++) dp[i][0] = 0;
for (int j = 0; j <= len2; j++) dp[0][j] = 0;
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (v1[i - 1] == v2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
dir[i][j] = 0;
} else if (dp[i - 1][j] > dp[i][j - 1]) {
dp[i][j] = dp[i - 1][j];
dir[i][j] = 1;
} else {
dp[i][j] = dp[i][j - 1];
dir[i][j] = -1;
}
}
}
printLCS(len1, len2);
printf("\n");
init();
}
return 0;
}