动态规划:合并回文字符串
题目链接:https://ac.nowcoder.com/acm/problem/13230
题目描述
输入两个字符串A和B,合并成一个串C,属于A和B的字符在C中顺序保持不变。如"abc"和"xyz"可以被组合成"axbycz"或"abxcyz"等。
我们定义字符串的价值为其最长回文子串的长度(回文串表示从正反两边看完全一致的字符串,如"aba"和"xyyx")。
需要求出所有可能的C中价值最大的字符串,输出这个最大价值即可
输入描述
第一行一个整数T(T ≤ 50)。
接下来2T行,每两行两个字符串分别代表A,B(|A|,|B| ≤ 50),A,B的字符集为全体小写字母。
输出描述
对于每组数据输出一行一个整数表示价值最大的C的价值。
示例
输入
2
aa
bb
a
aaaabcaa
输出
4
5
分析
本题采用区间dp。
给出转移方程:
设dp[i][j][k][l] 若a[i-1]到a[j-1] 和 b[k-1]到b[l-1] 所组成的字符串是回文则其值为1,否则为2。
dp[i][j][k][l]=dp[i+1][j-1][k][l] (a[i]a[j] && i<j)
dp[i][j][k][l]=dp[i][j][k+1][l-1] (b[k]b[l] && k<l)
dp[i][j][k][l]=dp[i+1][j][k][l-1] (a[i]b[l] && i<=j && k<=l)
dp[i][j][k][l]=dp[i][j-1][k+1][l] (a[j]b[k] && i<=j && k<=l)
初始化:
单独一个字符显然的回文的,没有字符我们也认为它是回文的(结合转移方程)。
因此,区间长度分别设为l1,l2。初始化的条件显然 l1+l2<=1 则dp=1
另外:
注意for循环的设置。
本题中的判断为几个并列的if,因此采用了同或,任一条件触发1,即为1。
AC代码
#include <string>
#include <iostream>
#include <cstring>
using namespace std;
#define maxn 52
int dp[maxn][maxn][maxn][maxn];
int main()
{
int n;
cin >> n;
while (n--)
{
memset(dp,0,sizeof(dp));
string a, b;
cin >> a >> b;
int max = 0;
for (int l1 = 0; l1 <= a.size(); l1++) //枚举长度
{
for (int l2 = 0; l2 <= b.size(); l2++) //枚举长度
{
for (int i = 1, j = l1; j <= a.size(); i++, j++) //枚举起点
{
for (int k = 1, l = l2; l <= b.size(); k++, l++) //枚举终点
{
if (l1 + l2 <= 1) //初始化 单个字符 空 均初始化为1
{
dp[i][j][k][l] = 1;
}
else
{
if (a[i - 1] == a[j - 1] && l1 > 1)
dp[i][j][k][l] |= dp[i + 1][j - 1][k][l];
if (b[k - 1] == b[l - 1] && l2 > 1)
dp[i][j][k][l] |= dp[i][j][k + 1][l - 1];
if (l1 && l2)
{
if (a[i - 1] == b[l - 1])
dp[i][j][k][l] |= dp[i + 1][j][k][l - 1];
if (a[j - 1] == b[k - 1])
dp[i][j][k][l] |= dp[i][j - 1][k + 1][l];
}
}
if (dp[i][j][k][l])
max = max > l1 + l2 ? max : l1 + l2;
}
}
}
}
cout << max << endl;
}
return 0;
}