Given three strings a, b and c, your mission is to check whether c is the combine string of a and b.
A string c is said to be the combine string of a and b if and only if c can be broken into two subsequences, when you read them as a string, one equals to a, and the other equals to b.
For example, “adebcf” is a combine string of “abc” and “def”.
Input
Input file contains several test cases (no more than 20). Process to the end of file.
Each test case contains three strings a, b and c (the length of each string is between 1 and 2000).
Output
For each test case, print “Yes”, if c is a combine string of a and b, otherwise print “No”.
Sample Input
abc
def
adebcf
abc
def
abecdf
Sample Output
Yes
No
题目大意:
给定三个字符串a,b,c。问c是否能恰好拆分成两个子序列,其中一个子序列等于a,另外一个子序列等于b。
核心思想:
动态规划。
如果a的前i个字符和b的前j个字符能结合成(子序列式结合,不是单纯的拼接)c的前i+j个字符,则dp[i][j]=1,否则,dp[i][j]=0。
状态转移方程:
a的第i个字符等于c的第i+j个字符,或者b的第j个字符等于c的第i+j个字符
dp[i][j]=dp[i-1][j]&&a[i]==c[i+j]||dp[i][j-1]&&b[j]==c[i+j]
另外,模拟会有bug的,例如:
ab
ac
acab
正确答案是Yes,模拟一般会No。
代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=2020;
char a[N],b[N],c[N];
bool dp[N][N];
int main()
{
while(scanf("%s%s%s",a,b,c)!=EOF)
{
int la=strlen(a);
int lb=strlen(b);
int lc=strlen(c);
if(la+lb!=lc)
{
printf("No\n");
continue;
}
//将字符都后移一位,方便初始化
for(int i=la;i>0;i--)
a[i]=a[i-1];
for(int i=lb;i>0;i--)
b[i]=b[i-1];
for(int i=lc;i>0;i--)
c[i]=c[i-1];
//初始化
dp[0][0]=1;
for(int i=1;i<=la;i++)
dp[i][0]=dp[i-1][0]&&a[i]==c[i];
for(int i=1;i<=lb;i++)
dp[0][i]=dp[0][i-1]&&b[i]==c[i];
//状态转移
for(int i=1;i<=la;i++)
for(int j=1;j<=lb;j++)
dp[i][j]=dp[i][j-1]&&b[j]==c[i+j]||dp[i-1][j]&&a[i]==c[i+j];
//输出
if(dp[la][lb])
printf("Yes\n");
else
printf("No\n");
}
return 0;
}