区间DP问题。与涂色问题大同小异,但如果想不明白就会觉得这两者有很大区别。

用一个四维数组dp[l1][r1][l2][r2]表示从第一个字符串中取l1到r1,从第二个字符串中取l2到r2是否能组成回文字符串,若不能则为0,能则为1。
状态转移方程分4种情况,因为字符串A、B有四种情况可以组成会问字符串。第一种是A在左B在右,直接拼接,若其能组成回文字符串,则有A[l1]==B[r2],此时有状态转移方程dp[l1][r1][l2][r2]|=dp[l1+1][r1][l2][r2-1];第二种是B在左,A在右,直接拼接,则有A[r1]==B[l2],此时有状态转移方程dp[l1][r1][l2][r2]|=dp[l1][r1-1][l2+1][r2];第三种情况是B插入A内部,A包住B,则有A[l1]==A[r1],此时有状态转移方程dp[l1][r1][l2][r2]|=dp[l1+1][r1-1][l2][r2];第四种情况是A插入B内部,B包住A,则有B[l2]==B[r2],此时有状态转移方程dp[l1][r1][l2][r2]|=dp[l1][r1][l2+1][r2-1]。
在循环迭代时要使用四重循环,外部两重控制A、B两个字符串取子串的长度,内部两重控制A、B两个字符串取子串的起点。四重循环就可以唯一决定取出的两个子串,再判断这两个子串是否能组成一个回文子串即可。
关于dp数组的初始状态,当仅选中一个字符或不选择字符时,认为它是回文的,所以在遍历中遇到未选择字符或仅选一个字符的情况,为其赋1。
关于判断的条件限制问题,要理解四种判断对应的情况,当情况是A包住B时,那么A的长度至少要为2,同理判断B包住A时B的长度至少为2。当情况是A左B右或B左A右时,A与B的长度都至少要为1。

另外有个下标的小坑,这里为了保证迭代过程中不发生越界,使数组的大小比数据范围的大小大了2,即n=n+2,这是为了应对在边界-1或+1时发生越界。这就使得l1r1在dp数组中表示A字符串中第l1个字符到第r1个字符。而在A数组中并没有做类似得扩容处理,所以A字符串中第l1个字符在A数组中为A[l1-1],第r1个字符为A[r1-1]。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main(){
    int T;
    cin >> T;
    for(int i = 0;i < T;i++){
        string A, B;
        cin >> A >> B;
        int n1 = A.size();
        int n2 = B.size();
        vector<int> temp1(n2 + 2, 0);
        vector<vector<int>> temp2(n2 + 2, temp1);
        vector<vector<vector<int>>> temp3(n1 + 2, temp2);
        vector<vector<vector<vector<int>>>> dp(n1 + 2, temp3);
        int res = 1;
        for(int step1 = 0;step1 <= n1;step1++){
            for(int step2 = 0;step2 <= n2;step2++){
                for(int l1 = 1;step1 + l1 - 1 <= n1;l1++){
                    for(int l2 = 1;step2 + l2 - 1 <= n2;l2++){
                        int r1 = step1 + l1 - 1;
                        int r2  = step2 + l2 - 1;
                        if(step1 + step2 <= 1){
                            dp[l1][r1][l2][r2] = 1;
                        }
                        else{
                            if(A[l1 - 1] == A[r1 - 1] && step1 > 1){
                                dp[l1][r1][l2][r2] |= dp[l1 + 1][r1 - 1][l2][r2];
                            }
                            if(A[l1 - 1] == B[r2 - 1] && step1 && step2){
                                dp[l1][r1][l2][r2] |= dp[l1 + 1][r1][l2][r2 - 1];
                            }
                            if(A[r1 - 1] == B[l2 - 1] && step1 && step2){
                                dp[l1][r1][l2][r2] |= dp[l1][r1 - 1][l2 + 1][r2];
                            }
                            if(B[l2 - 1] == B[r2 - 1] && step2 > 1){
                                dp[l1][r1][l2][r2] |= dp[l1][r1][l2 + 1][r2 - 1];
                            }
                            if(dp[l1][r1][l2][r2]){
                                res = max(res, step1 + step2);
                            }
                        }
                    }
                }
            }
        }
        cout << res <<endl;
    }
}