2013-04-24 10:10:43Morris

[UVA][dp、最長共同回文] 12473 - Common Palindrome

A palindrome is a string that reads the same from the left as it does from the right. Given two strings A and B, you need to find the length of longest palindrome which is a subsequence of both A and B. A subsequence is a sequence obtained by deleting zero or more characters from a string.

 

For example, say, A = “cfcfaafc”, B = “efagfc”. Then the longest palindrome which is a subsequence of both A and B is “faf”. So the answer is 3.

 

Input

First line of the input contains a positive integer T(T <= 100). Each of the following T cases consists of 2 lines. These 2 lines contain the strings A and B, respectively. Length of A and B will not be more than 60. All these strings contain only lowercase letters (‘a’ -‘z’). No empty strings will appear in the input.

 

Output

For each case, print a line of the form Case <x>: <y>, where x is the case number and y is the length of the longest common palindromic subsequence.

 

Sample Input

3

cfcfaafc

efagfc

afbcdfca

bcadfcgyfka

palin

drome

 

Sample Output

Case 1: 3

Case 2: 5

Case 3: 0


動態規劃 dp[la][ra][lb][rb] = 最長共同回文長度
[la, ra] 區間於 A string. [lb, rb] 區間於 B string.

因此很簡單地會發現
if(A[la] == A[ra] && B[lb] == B[rb] && A[la] == B[lb])
dp[la][ra][lb][rb] = dp[la+1][ra-1][lb+1][rb-1]+2
else
dp[la][ra][lb][rb] = max(dp[la+1][ra][lb][rb], dp[la][ra-1][lb][rb], dp[la][ra][lb+1][rb], dp[la][ra][lb][rb-1]);

因此算起來是 O(n^4), 60^4 算起來可以在 10 秒內通過。

//1.800 s

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
char dp[65][65][65][65];
int main() {
    int t, cases = 0;
    int i, j, k, p, q, r;
    int a1, b1, c1, d1;
    char A[105], B[105];
    scanf("%d", &t);
    while(t--) {
        scanf("%s %s", &A, &B);
        int la = strlen(A), lb = strlen(B);
        memset(dp, 0, sizeof(dp));
        for(i = 0; i < la; i++) {
            for(j = 0; j < lb; j++) {
                if(A[i] == B[j])
                    dp[i][i][j][j] = 1;
            }
        }
        for(i = 0; i < la; i++) {
            for(j = 0; i+j < la; j++) {
                for(p = 0; p < lb; p++) {
                    for(q = 0; p+q < lb; q++) {
                        if(A[j] == A[i+j] && B[q] == B[p+q] && p && i && A[j] == B[q]) {
                            dp[j][i+j][q][p+q] = dp[j+1][i+j-1][q+1][p+q-1]+2;
                            //printf("(%d %d %d %d)%d\n", j, i+j, q, p+q, dp[j+1][i+j-1][q+1][p+q-1]);
                        }
                        if(j+1 <= i+j)
                        dp[j][i+j][q][p+q] = max(dp[j][i+j][q][p+q], dp[j+1][i+j][q][p+q]);
                        if(j <= i+j-1)
                        dp[j][i+j][q][p+q] = max(dp[j][i+j][q][p+q], dp[j][i+j-1][q][p+q]);
                        if(q+1 <= p+q)
                        dp[j][i+j][q][p+q] = max(dp[j][i+j][q][p+q], dp[j][i+j][q+1][p+q]);
                        if(q <= p+q-1)
                        dp[j][i+j][q][p+q] = max(dp[j][i+j][q][p+q], dp[j][i+j][q][p+q-1]);
                        //printf("(%d %d %d %d) dp %d\n", j, i+j, q, p+q, (int)dp[j][i+j][q][p+q]);
                    }
                }
            }
        }
        printf("Case %d: %d\n", ++cases, dp[0][la-1][0][lb-1]);
    }
    return 0;
}
/*
5
gabgcccbadacg
gabxxxbacccgbadab
Case 1: 7
3
cfcfaafc
efagfc
afbcdfca
bcadfcgyfka
palin
drome
Case 1: 3
Case 2: 5
Case 3: 0
5
a
b
*/