HDU-5707 Combine String 动态规划

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(i1,j)&a[i]==c[i+j])(f(i,j1)&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");
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值