📅  最后修改于: 2023-12-03 15:42:22.686000             🧑  作者: Mango
这是门|门CS 2011年的问题1,是一道典型的动态规划问题。在这个问题中,我们需要在一个给定的序列中找到一个最长的子序列,这个子序列需要满足一些特定的条件。
给定两个长度分别为 $n,m$ 的序列 $A,B$,我们需要在 $A$ 中找到一个最长的子序列 $L$,满足以下条件:
例如,如果 $A={1,2,3}$ 和 $B={2,1,3}$,则 $L={1,3}$ 是一个合法的解,而 $L={2,3}$ 则不合法。
这是一道比较经典的动态规划问题。我们可以考虑把问题分成若干子问题,然后通过求解子问题来得到原问题的解。具体来说,我们可以定义一个二维数组 $dp_{i,j}$,其中 $dp_{i,j}$ 表示以 $A_i$ 和 $B_j$ 为结尾的最长子序列的长度。则我们要求的最长子序列的长度就是 $\max_{i,j} dp_{i,j}$。
开始时,所有的 $dp_{i,j}$ 均设置为0。然后,对于 $A_i$ 和 $B_j$,我们可以考虑以下两种情况:
而对于第一种情况,我们可以使用一个数组 $last_j$,其中 $last_j$ 表示 $B_j$ 在 $A$ 中最后一次出现的位置。这样,在求解 dp 值时,我们只需要枚举比 $B_j$ 小的 $A_k$ 的最大位置即可。
下面是这个问题的 C++ 代码实现:
int dp[MAX_N][MAX_M], last[MAX_M];
memset(dp, 0, sizeof(dp));
memset(last, -1, sizeof(last));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = dp[i][j - 1];
if (a[i] == b[j]) {
int k = last[j];
if (k != -1 && dp[k][j - 1] + 1 > dp[i][j]) {
dp[i][j] = dp[k][j - 1] + 1;
}
}
if (a[i] == b[j]) {
last[j] = i;
}
}
}
其中,$MAX_N$ 和 $MAX_M$ 分别表示序列的最大长度,$a$ 和 $b$ 分别表示两个序列。