24 ACwing 315 旅行 题解
旅行
题面
给定两个字符串 \(s, t\) ,求两个字符串的最长公共子序列,所有合法方案输出出来
\(1 \le |s| \le 80\)
题解
这题难点就在于求方案,那么如何求方案呢
我们可以写个dfs去推一下答案,为了方便我们倒着 dp,初始状态为 \(f(n,m)\) ,最终状态为 \(f(1, 1)\)
假如现在到了 \(i,j\) 那么下一个状态是什么?
如果 \(s[i] = t[j]\) 那么这个字母一定是最长公共子序列最前面的一个字母,所以下个状态是 \(i+1,j + 1\)
否则,我们肯定要在后面找到一个 \(x,y\) 使得 \(s[x] = t[y]\) ,我们可以暴力枚举一个字母,然后找到两个位置,如果 \(f[x][y] = f[i][j]\) 说明这就是下一个状态,否则说明不是
所以我们这样dfs就能求出最后的所有方案
时间复杂度不会算
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 100;
int n, m;
int f[N][N], len;
char s[N], t[N];
char ans[N];
void dfs (int p1, int p2, int cnt) {
if (cnt > len) {
printf ("%s\n", ans + 1);
return;
}
if (s[p1] == t[p2]) {
ans[cnt] = s[p1];
dfs (p1 + 1, p2 + 1, cnt + 1);
} else {
for (int i = 0; i < 26; i ++) {
int x = 0, y = 0;
for (int j = p1; j <= n; j ++) {
if (s[j] == 'a' + i) {
x = j;
break;
}
}
for (int j = p2; j <= m; j ++) {
if (t[j] == 'a' + i) {
y = j;
break;
}
}
if (f[x][y] == f[p1][p2]) {
ans[cnt] = s[x];
dfs (x + 1, y + 1, cnt + 1);
}
}
}
}
int main () {
scanf ("%s%s", s + 1, t + 1);
n = strlen (s + 1);
m = strlen (t + 1);
for (int i = n; i >= 1; i --) {
for (int j = m; j >= 1; j --) {
if (s[i] == t[j]) {
f[i][j] = f[i + 1][j + 1] + 1;
} else {
f[i][j] = max (f[i + 1][j], f[i][j + 1]);
}
}
}
len = f[1][1];
dfs (1, 1, 1);
return 0;
}