思路
① 扩展一个回文串,只要在首末各自加上一个相同的字符即可。
③ 求的是最长的回文子串长度,所以只要保存字符串A,B融合过程中的最大回文串长度就行。
②那么现在判断 A,B融合过程中的回文串
想要让 串 A 的 区间 i ~ j 和串B的区间 k ~ l 组成一个回文串,并且组成后的新字符串中 A ,B各自原字符相对位置不变,所以这个回文串 A[i] 一定在 A[j] 前面 ,B[k]一定在B[l] 前面 ,此时再回顾下 ① 那么这个回文串首末的的字符
组合有以下 4 种
1.A[i] = A[j] i 首 j末
2.B[k] = B[l] k首 l末
3.A[i] = B[l] i 首 l末
4.B[k] = A[j] k 首 j末
在这种情况下 只要保证 以上 4种任意一种除去首末字符后的子串仍是一个回文,且A,B各自字符顺序 不混乱的回文串, A 的 区间 i ~ j 和串B的区间 k ~ l 就可以组成一个回文串。你可以发现这是一个递归的问题于是便可以递归的解决这一个问题了。
④ 考虑边界问题
1.单个字符肯定是回文,
2.子问题是空串组成也算满足条件的回文
code
dfs
#include<bits/stdc++.h>
using namespace std;
#define IOS std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);// 快读
int dp[53][53][53][53];
string a,b;
int ans;
bool dfs(int i,int j,int k,int l){
// cout << i << " " << j << " " << k << " " << l << endl;
if(~dp[i][j][k][l])
return dp[i][j][k][l];
if(i == j && l == k)//空
return false;
if(j < i || l < k)//空
return false;
if(j - i == 1 && l - k == 1 && a[i-1] == b[k - 1]){//AB串各自剩下一个
ans = max(ans,2);
return true;
}
if((j - i == 1 && k == l) || (l - k == 1 && i == j) ){//A或B剩下一个字符,另一个串没有字符剩下
ans = max(1,ans);
return true;
}
if(j - i == 2 && k == l && a[i-1] == a[i]){//A串剩下2个字符
ans = max(2,ans);
return true;
}
if(l - k == 2 && i == j && b[k-1] == b[k]){//B串剩下2个字符
ans = max(2,ans);
return true;
}
bool f = false;
if(a[i-1] == a[j-2])
f |= dfs(i + 1,j - 1,k,l);
if(b[k - 1] == b[l - 2])
f |= dfs(i,j,k + 1,l - 1);
if(a[i-1] == b[l-2])
f |= dfs(i + 1,j,k,l - 1);
if(a[j-2] == b[k-1])
f |= dfs(i,j-1,k + 1,l);
//cout << f << endl;
if(f)
ans = max(ans,j - i + l - k);
return dp[i][j][k][l] = f;
}
int main(){
int T; cin >> T;
while(T--){
ans = 0;
memset(dp, -1 ,sizeof dp);
cin >> a >> b;
int az = a.size();
int bz = b.size();
for(int i = 1;i <= az; ++i)
for(int j = 1; j <= bz; ++j)
for(int v = 1; v <= az && v + i <= az + 1; ++ v)
for(int u = 1; u <= bz && u + j <= bz + 1; ++ u)
dfs(v,v + i,u,u + j);
cout << ans << endl;
}
return 0;
}
改成迭代 ,枚举区间长度即可,通过状态转移方程不难发现,长区间一定要由短区间来更新,所以先处理短区间,再处理长区间,所以枚举从小到大分别枚举两个串的长度即可
#include<bits/stdc++.h>
using namespace std;
bool dp[53][53][53][53];
int main(){
int T; cin >> T;
while(T--){
string a,b; cin >> a >> b;
int az = a.size(),bz = b.size();
int ans = 0;
for(int l1 = 0; l1 <= az; ++l1)
for(int l2 = 0; l2 <= bz; ++l2)
for(int i = 1; i + l1 - 1 <= az; ++i)//以i为起点 长度为l的区间 区间端点为 i + l - 1 对应字符位置 i + l -2
for(int j = 1; j + l2 - 1 <= bz; ++j){
bool f = false;
if(l1 + l2 <= 1)
f = true;
if(i + l1 - 2 >= 0 && a[i-1] == a[i + l1 - 2] && dp[i+1][i + l1 - 1][j][j + l2])
f = true;
if(j + l2 - 2 >= 0 && b[j-1] == b[j + l2 - 2] && dp[i][i + l1][j+1][j + l2 - 1])
f = true;
if(j + l2 - 2 >= 0 && a[i-1] == b[j + l2 - 2] && dp[i + 1][i + l1][j][j + l2 -1])
f = true;
if(i + l1 - 2 >= 0 && b[j-1] == a[i + l1 - 2] && dp[i][i + l1 - 1][j + 1][j + l2])
f = true;
dp[i][i + l1][j][j + l2] = f;
if(f)
ans = max(ans,l1 + l2);
}
cout << ans << endl;
}
return 0;
}