鏈接: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;
}