HDU-5707 Combine String
Problem Description
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
题目大意:
给你两个字符串队列和一个字符串,问你能不能用这两个队列生成第三个字符串。
我队友写这题的时候用了搜索加剪枝,还用了田忌赛马思想(HDU 1052)。结果不是WA就是TLE。后来我说是dp的时候他们整个人都崩溃了。
这道题目所有人第一眼都会觉得是两个队列依次判断对首元素是否等于下一个所需要的元素,是就出队,如果两个队列队首元素都不行就输出No。看似完美无缺,但实际上遗漏了两个队列队首元素相等时该出队哪一个的问题。
这题实际上可以用dp解决。设
f
(
i
,
j
)
f(i,j)
f(i,j)表示字符串
a
\text{a}
a 的前
i
i
i 个元素与字符串
b
\text{b}
b 的前
j
j
j 个元素能否凑成c的前
i
+
j
i+j
i+j 个元素,则状态转移方程为:
f
(
i
,
j
)
=
(
f
(
i
−
1
,
j
)
&
a
[
i
]
=
=
c
[
i
+
j
]
)
∣
(
f
(
i
,
j
−
1
)
&
b
[
j
]
=
=
c
[
i
+
j
]
)
f(i,j)=(f(i-1,j) \&a[i]==c[i+j]) | (f(i,j-1) \& b[j]==c[i+j])
f(i,j)=(f(i−1,j)&a[i]==c[i+j])∣(f(i,j−1)&b[j]==c[i+j])
这样子一来,这题就很简单了。
废话少说,上代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define maxn 2000+5
bool dp[maxn][maxn];
char a[maxn], b[maxn], c[maxn*2];
int main()
{
int l1, l2;
while(cin.getline(a,maxn)){
cin.getline(b,maxn);
cin.getline(c,maxn);
memset(dp,false,sizeof(dp));
for(int i=0;i<maxn;i++) dp[i][0]=dp[0][i]=0;
l1=strlen(a), l2=strlen(b);
if(l1+l2 != strlen(c)) {printf("No\n");continue;}
for(int i = l1; i > 0; i--) a[i] = a[i-1];
for(int i = l2; i > 0; i--) b[i] = b[i-1];
for(int i = strlen(c); i > 0; i--) c[i] = c[i-1];
dp[0][0] = true;
for(int i = 1; i <= l1; i++)
dp[i][0] = dp[i-1][0] & (a[i]==c[i]);
for(int i = 1; i <= l2; i++)
dp[0][i] = dp[0][i-1] & (b[i]==c[i]);
for(int i = 1; i <= l1; i++){
for(int j = 1; j <= l2; j++){
if(a[i] == c[i+j] && dp[i-1][j]) dp[i][j] = true;
if(b[j] == c[i+j] && dp[i][j-1]) dp[i][j] = true;
}
}
printf(dp[l1][l2]?"Yes\n":"No\n");
}
}