题意
给定两个字符串,各取出一个子串接在一起,求最长回文子串的长度。
solution
先考虑普通的求最长回文子串的dp做法:
表示子串 是否为回文串。
那么,容易得到: && 。
由于 是由 转移过来的,所以我们需要倒着遍历:
Code
for (int i = s.size() - 1; i >= 0; i--) for (int j = i; j < s.size(); j++) { if (s[i] == s[j] && (j - i < 2 || dp[i + 1][j - 1])) { dp[i][j] = true; res = max(res, j - i + 1); } }
那么这题其实可以类比:
表示a串第i个字符到第j个字符和b串第k个字符到第l个字符是否组成回文串:
往 到 和 到 构成的串的两端加上 和 两个字符:
往 到 和 到 构成的串的两端加上 和 两个字符:
往 到 和 到 构成的串的两端加上 和 两个字符:
往 到 和 到 构成的串的两端加上 和 两个字符:
实际上就是取法由原来的一种变为了四种,注意若组成的字符串长度小于2时需要直接赋值为1
Code
#include <bits/stdc++.h> using namespace std; const int N = 105; char a[N], b[N]; bool f[N][N][N][N]; int t, n, m; int main() { scanf("%d", &t); while (t--) { int res = 0; scanf("%s", a + 1); scanf("%s", b + 1); n = strlen(a + 1); m = strlen(b + 1); for (int len1 = 0; len1 <= n; len1++) //枚举a串的长度 for (int len2 = 0; len2 <= m; len2++) //枚举b串的长度 for (int i = 1; i + len1 - 1 <= n; i++) for (int k = 1; k + len2 - 1 <= m; k++) { int j = i + len1 - 1, l = k + len2 - 1; //根据左端点和长度计算右端点 if (len1 + len2 <= 1) f[i][j][k][l] = 1; else { f[i][j][k][l] = 0; if (len1 > 1) f[i][j][k][l] |= (f[i + 1][j - 1][k][l] && (a[i] == a[j])); if (len1 && len2) f[i][j][k][l] |= (f[i + 1][j][k][l - 1] && (a[i] == b[l])); if (len1 && len2) f[i][j][k][l] |= (f[i][j - 1][k + 1][l] && (a[j] == b[k])); if (len2 > 1) f[i][j][k][l] |= (f[i][j][k + 1][l - 1] && (b[k] == b[l])); } if (f[i][j][k][l]) res = max(res, len1 + len2); } printf("%d\n", res); } return 0; }