link 输入两个字符串A和B( ∣ A ∣ , ∣ B ∣ < 50 |A|, |B| < 50 ∣A∣,∣B∣<50 ),合并成一个串C,属于A和B的字符在C中顺序保持不变。如"abc"和"xyz"可以被组合成"axbycz"或"abxcyz"等。 我们定义字符串的价值为其最长回文子串的长度(回文串表示从正反两边看完全一致的字符串,如"aba"和"xyyx")。需要求出所有可能的C中价值最大的字符串,输出这个最大价值。
若是这题暴力把所有合成的 C 串找出来,则共有 C 100 50 C_{100}^{50} C10050 种可能,这种指数复杂度是不能承受的。而类比找一个字符串的回文串,若是只是单个字符串,我们可以通过dp进行 O ( n 2 ) O(n^2) O(n2) 的算法:
//字符串从s[1]开始存储,长度为len for(int L = 1; L <= len; L++) { for(int i = 1; i + L - 1 <= len; i++) { int j = i + L - 1; if(s[i] == s[j] && (L <= 2 || dp[i+1][j-1])) { dp[i][j] = 1; ans = max(ans, L); } } }若是要用动态规划,区间dp的思想是考虑从小规模的状态转移到大规模的状态,因此肯定是从长度较小的回文子串转移到长度较大的回文子串,即如果一个回文串首尾加上同样的字母,可以构成一个新的更长的回文串。 若是用 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示区间 [ i , j ] [i, j] [i,j] 构成的子串是不是回文串(01表示),那么一个区间是回文串有以下三种可能: ① i = j i = j i=j,即单个字符是回文串; ② i = j − 1 i = j - 1 i=j−1 并且 s [ i ] = s [ j ] s[i] = s[j] s[i]=s[j],即两个一样的字符是回文串; ③ i < j − 1 i < j - 1 i<j−1 并且 s [ i ] = s [ j ] , d p [ i + 1 ] [ j − 1 ] = 1 s[i] = s[j],\ dp[i+1][j-1] = 1 s[i]=s[j], dp[i+1][j−1]=1,即一个回文串首尾加上同样的字母,可以构成一个新的更长的回文串。 因此若是求单个字符串的回文子串,大循环是区间长度,小循环是区间起始位置进行双重循环就行,当然还有更优秀的马拉车算法( O ( n ) O(n) O(n)) 。 对于这一题,我们需要考虑的是两个字符串组合得到的回文串,则需要四维 d p [ i ] [ k ] [ j ] [ l ] dp[i][k][j][l] dp[i][k][j][l], 表示 A [ i ] [ k ] , B [ j ] [ l ] A[i][k], B[j][l] A[i][k],B[j][l] 是否可以组成一个回文串。记 l e n 1 = k − i + 1 , l e n 2 = l − j + 1 len_1 = k - i + 1, \ len_2 = l - j + 1 len1=k−i+1, len2=l−j+1, 同样地,我们需要考虑状态转移: ①如果 l e n 1 + l e n 2 ≤ 1 len_1 + len_2 ≤ 1 len1+len2≤1, 则 d p [ i ] [ k ] [ j ] [ l ] dp[i][k][j][l] dp[i][k][j][l] 为 1。等于 1 时两个字符串的截取一个为空,一个长度为1,自然是回文串;等于 0 时两个字符串都截取为空,其实是没有回文串的定义的,但是为了之后的转移方便(如从 d p [ 0 ] [ 0 ] [ 0 ] [ 0 ] dp[0][0][0][0] dp[0][0][0][0] 转移到 d p [ 1 ] [ 1 ] [ 1 ] [ 1 ] dp[1][1][1][1] dp[1][1][1][1]), 定义为1。 ②如果 l e n 1 > 1 len_1 > 1 len1>1, 那么对于 d p [ i ] [ k ] [ j ] [ l ] dp[i][k][j][l] dp[i][k][j][l], 若 A [ i ] = A [ k ] A[i] = A[k] A[i]=A[k] 且 d p [ i + 1 ] [ k − 1 ] [ j ] [ l ] = 1 dp[i+1][k-1][j][l] = 1 dp[i+1][k−1][j][l]=1,那么首尾加上 A [ i ] , A [ k ] A[i] ,A[k] A[i],A[k]还是回文串,则 d p [ i ] [ k ] [ j ] [ l ] = 1 dp[i][k][j][l] = 1 dp[i][k][j][l]=1 。同理对于 l e n 2 > 1 len_2 > 1 len2>1。 ③如果 l e n 1 > 0 len_1 > 0 len1>0 且 l e n 2 > 0 len_2 > 0 len2>0, 若 A [ i ] = B [ l ] A[i] = B[l] A[i]=B[l] 且 d p [ i + 1 ] [ k ] [ j ] [ l − 1 ] = 1 dp[i+1][k][j][l-1] = 1 dp[i+1][k][j][l−1]=1, 那么在首尾加上 A [ i ] , B [ l ] A[i], B[l] A[i],B[l] 还是回文串,则 d p [ i ] [ k ] [ j ] [ l ] = 1 dp[i][k][j][l] = 1 dp[i][k][j][l]=1 。同理对于 A [ k ] = B [ j ] A[k] = B[j] A[k]=B[j] 且 d p [ i ] [ k − 1 ] [ j + 1 ] [ l ] = 1 dp[i][k-1][j+1][l] = 1 dp[i][k−1][j+1][l]=1。 所以以上就得出了从小回文串转移到大回文串的区间动态规划过程。通过四重循环,前两重为A, B串截取的长度,后两重为 A, B串的区间起始位置,在计算时记录最大值就可以解决了。
除了转移方程,还需要特别注意动态规划过程边界的处理。