http://acm.hdu.edu.cn/showproblem.php?pid=4681
蛮好……
一开始有这样的想法: dp[i][j][k]=lcs(A[1..i],B[1..j]),ending with C[1...k] ,不过当然是过不了的。
其实
C
没有必要分开考虑,只要找到有
具体说来就是:
lcs_lft[i][j]=lcs(A[1..i],B[1..j])lcs_rit[i][j]=lcs(A[i..n],B[j..m])
A 的每个位置
i 有一个 j=nexta[i] 的位置,表示 A[i..j] 有一个 C 做子序列并且j 尽量小;同理有 nextb[] 。result=max(lcs_lft[i−1][j−1]+lcs_rit[nexta[i]+1][nextb[j]+1])+strlen(C)
#include <bits/stdc++.h>
const int N = 1024;
char a[N];
char b[N];
char c[N];
int lcs_lft[N][N];
int lcs_rit[N][N];
int nexta[N];
int nextb[N];
void lcs_table(int n, int m)
{
memset(lcs_lft, 0, sizeof(lcs_lft));
memset(lcs_rit, 0, sizeof(lcs_rit));
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
lcs_lft[i][j] = std::max(lcs_lft[i - 1][j], lcs_lft[i][j - 1]);
if (a[i] == b[j])
lcs_lft[i][j] = std::max(lcs_lft[i - 1][j - 1] + 1, lcs_lft[i][j]);
}
}
for (int i = n; i >= 1; --i)
{
for (int j = m; j >= 1; --j)
{
lcs_rit[i][j] = std::max(lcs_rit[i + 1][j], lcs_rit[i][j + 1]);
if (a[i] == b[j])
lcs_rit[i][j] = std::max(lcs_rit[i + 1][j + 1] + 1, lcs_rit[i][j]);
}
}
}
void next_table(int n, int m)
{
for (int i = 1; i <= n; i++)
{
int len = 0;
nexta[i] = -1;
for (int j = i; j <= n; j++)
{
if (a[j] == c[len + 1])
{
len++;
if (c[len + 1] == '\0')
{
nexta[i] = j;
break;
}
}
}
}
for (int i = 1; i <= m; i++)
{
int len = 0;
nextb[i] = -1;
for (int j = i; j <= m; j++)
{
if (b[j] == c[len + 1])
{
len++;
if (c[len + 1] == '\0')
{
nextb[i] = j;
break;
}
}
}
}
}
int max_length(int n, int m)
{
int res = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int ii = nexta[i];
int jj = nextb[j];
if (ii < 0 || jj < 0)
continue;
int tmp = lcs_lft[i - 1][j - 1] + lcs_rit[ii + 1][jj + 1];
res = std::max(res, tmp);
}
}
res += strlen(c + 1);
return res;
}
int main()
{
int casc;
scanf("%d", &casc);
for (int casi = 1; casi <= casc; casi++)
{
scanf("%s %s %s", a + 1, b + 1, c + 1);
int n = strlen(a + 1);
int m = strlen(b + 1);
lcs_table(n, m);
next_table(n, m);
printf("Case #%d: %d\n", casi, max_length(n, m));
}
return 0;
}