1. 程式人生 > 其它 >[NC13230]合併迴文子串

[NC13230]合併迴文子串

一、題目描述

NC13230
輸入兩個字串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的價值。

二、思路

區間dp
1.dp陣列的下標及其定義:
用四維ijkl來表示狀態,dp[i][j][k][l]的定義為字串a中ij區間能否和字串b中k

l區間組成迴文串
2.狀態轉移方程:
四種情況分別是:a[j] == a[i], a[j] == b[k], b[l] == a[i], b[l] == b[k]
因此就有四條性質類似的方程:

                        往a[i + 1] ~ a[j - 1] 與 b[k] ~ b[l] 兩端加入a[i] 和 a[j]
                         if(dp[i + 1][j - 1][k][l]) dp[i][j][k][l] = 1;
        
                        往a[i] ~ a[j - 1] 與 b[k + 1] ~ b[l] 兩端加入b[k] 和 a[j]
                         if(dp[i][j - 1][k + 1][l]) dp[i][j][k][l] = 1;

                        往a[i + 1] ~ a[j] 與 b[k] ~ b[l - 1] 兩端加入a[i] 和 b[l]
                         if(dp[i + 1][j][k][l - 1]) dp[i][j][k][l] = 1;

                        往a[i] ~ a[j] 與 b[k + 1] ~ b[l - 1] 兩端加入b[k] 和 b[l]
                         if(dp[i][j][k + 1][l - 1]) dp[i][j][k][l] = 1;

3.遍歷順序
要將每種情況遍歷到,用四層迴圈,第一層是a字串的迴文串長度,第二層是b字串的迴文串長度,第三層是a的左右端點i,j,第四層是b的左右端點k,l
4.dp陣列如何初始化
開始時先全初始化為0,在遍歷時判斷如果迴文串長度是0的時候直接改成1就好,代表由單個字元組成的迴文串

三、程式碼

#include<bits/stdc++.h>
using namespace std;
char a[100], b[100];
int dp[110][110][110][110];
int main(){
	int t;
	cin >> t;
	while(t --){
		scanf("%s", a + 1);
		scanf("%s", b + 1);
		memset(dp, 0, sizeof dp);
		int ans = 0;
		int lena = strlen(a + 1), lenb = strlen(b + 1);
		for(int d1 = 0; d1 <= lena; d1 ++){ //d1為選取的a字串中的長度 
			for(int d2 = 0; d2 <= lenb; d2 ++){ //d2為選取的b字串中的長度 
				for(int i = 1, j = d1; j <= lena; i ++, j ++){ //i, j為a字串所選區間的左右端點 
					for(int k = 1, l = d2; l <= lenb; k ++, l ++){ //k, l為b字串所選區間的左右端點 
						if(d1 + d2 <= 1) dp[i][j][k][l] = 1; //只有單個字元作為迴文串 
						else {
							if(a[j] == a[i] && d1 > 1){
								if(dp[i + 1][j - 1][k][l]) dp[i][j][k][l] = 1; //判斷i + 1~j - 1段與k ~ l段能否組成迴文串, 以下同理 
							}
							if(a[j] == b[k] && d1 && d2){
								if(dp[i][j - 1][k + 1][l]) dp[i][j][k][l] = 1;
							}
							if(b[k] == b[l] && d2 > 1){
								if(dp[i][j][k + 1][l - 1]) dp[i][j][k][l] = 1; 
							} 
							if(b[l] == a[i] && d1 && d2){
								if(dp[i + 1][j][k][l - 1]) dp[i][j][k][l] = 1;
							}
						}
						//cout << dp[i][j][k][l];
						if(dp[i][j][k][l]) ans = max(ans, d1 + d2);
					}
					//cout << endl;
				}
			}
		} 
		cout << ans << endl;
	}
	return 0;
}