题目大意:找到一个字符串D,使得D是字符串A的子序列,D是字符串B的子序列,同时C是D的子串(PS:请注意子串与子序列的区别)
解题思路:首先求出A、B的最长公共子序列, 和A、B逆序的最长公共子序列,分别用数组 max1 和 max2 记录。然后分别在字符串A和B中找到C串的个数,假设分别为n、m,并记录在A、B串中每找到的C串的起始和终止位置,分别放在数组sa、ja、sb、jb,枚举每种组合情况。求出max1[sa][sb] + max2[ la - ja - 1 ][ lb - jb -1 ] + lc 的最大值 即为最后结果。(其中la 、lb、 lc分别为A、B、C串的长度)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 1010
char a[N], b[N], c[N], ra[N],rb[N], x[N];
int sa[N], sb[N], ja[N], jb[N];
int max1[N][N], max2[N][N];
void LCS(char p[],char q[],int ma[][N])
{
int l1 = strlen(p);
int l2 = strlen(q);
int i, j;
for(i = 0; i < N; i ++)
{
ma[i][0] = 0;
ma[0][i] = 0;
}
for(i = 0; i < l1; i ++)
{
for(j = 0; j < l2; j ++)
{
if(p[i] == q[j])
ma[i+1][j+1] = ma[i-1+1][j-1+1] + 1;
else
{
int ll1 = ma[i+1][j-1+1];
int ll2 = ma[i-1+1][j+1];
if(ll1 > ll2) ma[i+1][j+1]=ll1;
else ma[i+1][j+1]=ll2;
}
}
}
}
int GetNum(int *s, int *j1, char *x, char *y)
{
memset(s, -1, sizeof(s));
memset(j1, -1, sizeof(j1));
int l = strlen(x);
int lc = strlen(y);
int j=0, k=0;
for(int i = 0; i < l; i ++)
{
if(x[i] == y[j])
{
j ++;
if(j == 1) s[k] = i;
if(j == lc)
{
j1[k] = i;
j = 0;
i = s[k] ;
k ++;
}
}
}
if(j1[k-1] == -1)
{
k --;
}
return k;
}
int main()
{
int t;
scanf("%d", &t);
int cases = 1;
while(t--)
{
scanf("%s %s %s", a, b, c);
int la = strlen(a);
int lb = strlen(b);
int lc = strlen(c);
int s1, j1, s2, j2;
for(int i = la - 1; i >= 0; i --)
ra[la-i-1] = a[i];
ra[la] = '\0';
for(int i = lb - 1; i >= 0; i--)
rb[lb-i-1] = b[i];
rb[lb] = '\0';
int ka = GetNum(sa, ja, a, c);
int kb = GetNum(sb, jb, b, c);
LCS(a, b, max1);
LCS(ra, rb, max2);
int ans = 0;
for(int o = 0 ; o < ka ;o ++ )
{
for(int p = 0; p < kb ; p ++)
{
s2 = sb[p];j2 = jb[p];
s1 = sa[o];j1 = ja[o];
int ans1 = max1[s1][s2];
int ans2 = max2[la-j1-1][lb-j2-1];
ans = max(ans ,lc + ans1 + ans2);
}
}
printf("Case #%d: %d\n",cases++ , ans);
}
return 0;
}