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;
}
posted @ 2025-10-05 18:06  michaele  阅读(8)  评论(0)    收藏  举报