Problem
Cameron and Jamie are about to welcome a second baby into their lives. They are already good at working together as parents, but right now they are disagreeing about one crucial thing! Cameron wants to name the baby one name (the string C), whereas Jamie wants to name the baby something else (the string J).
You want to help them find a compromise name that is as close as possible to what each of them wants. You think you can do this using the notion of edit distance. The edit distance between two strings S1 and S2 is the minimum number of operations required to transform S1 into S2, where the allowed operations are as follows:
Insert one character anywhere in the string.
Delete one character from anywhere in the string.
Change one character in the string to any other character.
For example, the edit distance between CAMERON and JAMIE is 5. One way to accomplish the transformation in 5 steps is the following: CAMERON to JAMERON (change) to JAMIERON (insert) to JAMIEON (delete) to JAMIEN (delete) to JAMIE (delete). Any transformation from CAMERON into JAMIE requires at least this many operations.
To make the compromise name N as close as possible to the original desires of the parents, you want N to be a non-empty string such that the sum of the edit distances between C and N and between J and N is as small as possible. Out of all those choices for N, to make sure the compromise is fair, you must choose an N such that the difference between those two edit distances is also as small as possible. Please find a compromise name for Cameron and Jamie.
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each case consists of a single line with two strings C and J: the names that Cameron and Jamie have proposed for the baby, respectively. Each of these names is made up of uppercase English alphabet letters.
Output
For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is a name that meets the requirements mentioned in the statement. Note that y must contain only uppercase English letters.
Limits
Time limit: 20 seconds per test set.
Memory limit: 1GB.
1 ≤ T ≤ 100.
C ≠ J.
Test Set 1 (Visible Verdict)
1 ≤ length of C ≤ 6.
1 ≤ length of J ≤ 6.
The i-th letter of C is an uppercase X, Y, or Z, for all i.
The i-th letter of J is an uppercase X, Y, or Z, for all i.
Test Set 2 (Hidden Verdict)
1 ≤ length of C ≤ 60.
1 ≤ length of J ≤ 60.
The i-th letter of C is an uppercase English alphabet letter, for all i.
The i-th letter of J is an uppercase English alphabet letter, for all i.
Sample
Input
Output
4
XYZZY ZZYZX
Y Z
YYXXYZ ZYYXXY
XZXZXZ YZ
Case #1: ZZY
Case #2: Z
Case #3: ZYYXXYZ
Case #4: ZYZX
The above cases meet the limits for Test Set 1. Another sample case that does not meet those limits appears at the end of this section.
In Sample Case #1, the edit distance from XYZZY to ZZY is 2 (delete the first two letters), and the edit distance from ZZYZX to ZZY is 2 (delete the last two letters). XZZX and ZYYZY would also work. No possible name has a sum of edit distances that is less than 4.
ZY, for example, has the same edit distance to C as to J (3, in each case). However the sum of those distances would be 6, which is not minimal, so it would not be an acceptable answer.
XZZY is also unacceptable. Its edit distances to C and J, respectively, are 1 and 3. The sum of those edit distances is minimal, but the difference between the two (|1-3| = 2) is not minimal, since we have shown that it is possible to achieve a difference of 0.
In Sample Case #2, Y and Z are the only acceptable answers.
In Sample Case #3, notice that input length restrictions do not apply to the output, so the shown answer is acceptable in either test set. Another possible answer is YYXXY.
In Sample Case #4, the edit distance between XZXZXZ and ZYZX is 3, and the edit distance between YZ and ZYZX is 2. The sum of those edit distances is 5, and their difference is 1; these values are optimal for this case.
The following additional case could not appear in Test Set 1, but could appear in Test Set 2.
1
GCJ ABC
Case #1: GC is one of the possible correct outputs.
dp,
我们从
s
s
s开始
f
i
,
j
f_{i,j}
fi,j表示第
s
[
1..
i
]
s[1..i]
s[1..i]变成
t
[
1..
j
]
t[1..j]
t[1..j]的最小代价。
记录dp的路径
p
a
t
h
path
path,1表示删
s
s
s的字母,
2
2
2表示添
t
t
t中的字母,
3
3
3表示将
s
s
s的一个字母变化成
t
t
t一个字母(两个字母可以相同)。
显然答案是
s
s
s变成
t
t
t变化过程的中间情况。
#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
For(j,m-1) cout<<a[i][j]<<' ';\
cout<<a[i][m]<<endl; \
}
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int MAXSTRLEN = 100;
char s[1010],t[1010];
int f[102][102]={};
int path[MAXSTRLEN][MAXSTRLEN];
void PrintLcs(int i, int j,int p)
{
if (i == 0 && j == 0) return;
if(p==0) {
if (path[i][j] == 3)
{
int fl=(s[i]!=t[j]);
PrintLcs(i - 1, j - 1,0);
putchar(t[j]);
}
else if (path[i][j] == 1) PrintLcs(i - 1, j,0);
else PrintLcs(i, j - 1,0),putchar(t[j]);
}else {
if (path[i][j] == 3)
{
int fl=(s[i]!=t[j]);
PrintLcs(i - 1, j - 1,p-fl);
putchar(s[i]);
}
else if (path[i][j] == 1) PrintLcs(i - 1, j,p-1),putchar(s[i]);
else PrintLcs(i, j - 1,p-1);
}
}
int main()
{
freopen("A.in","r",stdin);
// freopen(".out","w",stdout);
int T=read();
For(kcase,T){
printf("Case #%d: ",kcase);
cin>>(s+1)>>(t+1);
int n=strlen(s+1),m=strlen(t+1);
f[0][0]=0;
Rep(i,n+1)Rep(j,m+1)if(i+j) {
if(i==0) f[i][j]=j,path[i][j]=2;
else if(j==0) f[i][j]=i,path[i][j]=1;
else {
f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1);
f[i][j]=min(f[i][j],f[i-1][j-1]+(s[i]!=t[j]));
if(f[i][j]==f[i-1][j-1]+(s[i]!=t[j])) {
path[i][j]=3;
}else if (f[i][j]==f[i-1][j]+1) {
path[i][j]=1;
}else path[i][j]=2;
}
}
int p=f[n][m]-f[n][m]/2;
PrintLcs(n,m,p);
cout<<endl;
}
return 0;
}