合并回文子串 (区间DP)

合并回文子串

题目描述 :
输入两个字符串A和B,合并成一个串C,属于A和B的字符在C中顺序保持不变。如"abc"和"xyz"可以被组合成"axbycz"或"abxcyz"等。
我们定义字符串的价值为其最长回文子串的长度(回文串表示从正反两边看完全一致的字符串,如"aba"和"xyyx")。
需要求出所有可能的C中价值最大的字符串,输出这个最大价值即可。

输入描述:
第一行一个整数T(T ≤ 50)。
接下来2T行,每两行两个字符串分别代表A,B(|A|,|B| ≤ 50),A,B的字符集为全体小写字母。

思路: 首先类比求单独一个字符串的最长回文子串的区间DP的方法,即二维DP维护即可
状态转移方程:

if(s[i-1]==s[j-1]) dp[i][j] = dp[i+1][j-1]
else dp[i][j] = 0
(以小区间拓展到大区间)

此题由两个字符串保持原序列的条件下,组成一个最长的回文子串,所以我们用四维DP,且同样的用0,1表示状态,那么除去边界情况,每次状态转移就只有四种选择 (可以手动画一下区间)。

所以本题状态转移方程
if(s1[i-1]==s1[j-1]) dp[i][j][k][l] |=dp[i+1][j-1][k][l];
if(s1[i-1]==s2[l-1]) dp[i][j][k][l] |=dp[i+1][j][k][l-1];
if(s2[k-1]==s2[l-1]) dp[i][j][k][l] |=dp[i][j][k+1][l-1];
if(s2[k-1]==s1[j-1]) dp[i][j][k][l] |=dp[i][j-1][k+1][l];

dp[i][j][k][l] 表示 s1 字符串的 i - j 区间和 s2 字符串的 k - l 区间是否能够构成回文数组

Code:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 55;

int dp[N][N][N][N];

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		string s1,s2;
		cin>>s1>>s2;
		int len1 = s1.size();
		int len2 = s2.size();
		int ans = 0;
		for(int x = 0;x <= len1; x++)	//枚举长度
			for(int y = 0;y <= len2; y++)	//枚举长度
				for(int i=1,j=x;j<=len1;i++,j++)	//枚举区间
					for(int k=1,l=y;l<=len2;k++,l++){	//枚举区间
						if(x+y<=1) dp[i][j][k][l] = 1;	//单独一个字母是回文
						else{
							dp[i][j][k][l] = 0;			//多组读入 初始化
							if(x>1 && s1[i-1]==s1[j-1] && dp[i+1][j-1][k][l]) 
								dp[i][j][k][l] = 1;
							if(y>1 && s2[k-1]==s2[l-1] && dp[i][j][k+1][l-1])  
								dp[i][j][k][l] = 1;
							if(x &&y && s1[i-1]==s2[l-1] && dp[i+1][j][k][l-1])
								dp[i][j][k][l] = 1;
							if(x &&y && s2[k-1]==s1[j-1] && dp[i][j-1][k+1][l])	//四种状态转移
								dp[i][j][k][l] = 1;
						}
						if(dp[i][j][k][l]) ans= max(ans,x+y);
						// 意味着区间i~j 和k~l 能构成回文,则长度为(j-i+1 + k-l+1) 即 (x+y) 
					}
		cout<<ans<<endl;
	}
	return 0;
 } 
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值