链接: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的价值。
示例1
输入
2
aa
bb
a
aaaabcaa
输出
4
5
很明显这道题是dp题,因为我们假设dp[i][j][k][p]表示的是选择字符串a第i到j,字符串b第k到p的串。我们来思考下状态转移方程!
当a[i]==a[j]的时候,这个时候,最长的回文串是什么?毫无疑问,将a[i]与a[j]拼接到串a[i+1][j-1][k][p]当中即可。
当a[i]==b[p],b[k]==a[j],b[k]==b[p]都是如此。
注意写区间dp要从小区间更新大区间,那怎么做呢?枚举区间长度即可!(边界处理有点难)
#include<iostream>
#include<cstdio>
#define mmax 55
using namespace std;
int dp[55][55][55][55];
int main (){
int T;
cin>>T;
while(T--){
string a,b;
cin>>a>>b;
int len1=a.size();
int len2=b.size();
int inf=0;
for(int i=0;i<=len1;i++){//第一段区间的长度
for(int j=0;j<=len2;j++){//第二段区间的长度
for(int k=0;k<=len1;k++){//第一段区间的起点,这里要多出来一个空间
int xend=k+i;//第一段区间终点+1
if(xend>len1){//终点超出数组长度
break;
}
for(int p=0;p<=len2;p++){//第二段区间的起点
int yend=p+j;
if(yend>len2){
break;
}
int x=k,y=p;
if(i+j<=1){//不管选不选,小于等于一个字母一定是回文串
dp[x][xend][y][yend]=1;
}
else{
dp[x][xend][y][yend]=0;
if(x<=xend-2&&a[x]==a[xend-1]){
dp[x][xend][y][yend]|=dp[x+1][xend-1][y][yend];
}
if(x+1<=xend&&y<=yend-1&&a[x]==b[yend-1]){
dp[x][xend][y][yend]|=dp[x+1][xend][y][yend-1];
}
if(x<=xend-1&&y+1<=yend&&b[y]==a[xend-1]){
dp[x][xend][y][yend]|=dp[x][xend-1][y+1][yend];
}
if(y<=yend-2&&b[y]==b[yend-1]){
dp[x][xend][y][yend]|=dp[x][xend][y+1][yend-1];
}
}
if(dp[x][xend][y][yend])
inf=max(inf,i+j);
// printf("%d %d %d %d %d\n",x,xend,y,yend,dp[x][xend][y][yend]);
}
}
}
}
cout<<inf<<endl;
}
return 0;
}