HDU--杭电--1501--Zipper--深搜、DP都好

14 篇文章 0 订阅

Zipper

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5807    Accepted Submission(s): 2086


Problem Description
Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order.

For example, consider forming "tcraete" from "cat" and "tree":

String A: cat
String B: tree
String C: tcraete


As you can see, we can form the third string by alternating characters from the two strings. As a second example, consider forming "catrtee" from "cat" and "tree":

String A: cat
String B: tree
String C: catrtee


Finally, notice that it is impossible to form "cttaree" from "cat" and "tree".
 

Input
The first line of input contains a single positive integer from 1 through 1000. It represents the number of data sets to follow. The processing for each data set is identical. The data sets appear on the following lines, one data set per line.

For each data set, the line of input consists of three strings, separated by a single space. All strings are composed of upper and lower case letters only. The length of the third string is always the sum of the lengths of the first two strings. The first two strings will have lengths between 1 and 200 characters, inclusive.

 

Output
For each data set, print:

Data set n: yes

if the third string can be formed from the first two, or

Data set n: no

if it cannot. Of course n should be replaced by the data set number. See the sample output below for an example.
 

Sample Input
  
  
3 cat tree tcraete cat tree catrtee cat tree cttaree
 

Sample Output
  
  
Data set 1: yes Data set 2: yes Data set 3: no
 
题意:输入三个字符串,前两个随意交错排列看能不能形成第三个

思路:本题有缺陷,就是测试数据弱爆了,所以直接暴力深搜加几个特解就能过,不过暴力深搜的就没给代码了,直接是平常深搜的代码,然后是DP的代码,解释在代码中




深搜:
#include <iostream>
#include <cstring>
using namespace std;
char s1[222],s2[222],s3[444];
int l1,l2,visit[222][222];
bool dfs(int i,int j,int k)
{
    if(k==l1+l2)return 1;	//s3的下标等于s1加s2长度的时候就表示搜完了
    if(visit[i][j])return 0;	//这一步很重要,没了他就超时,深搜讲究的就是不重复搜同一个点
    visit[i][j]=1;
    if(i<l1&&s1[i]==s3[k]&&dfs(i+1,j,k+1))return 1;	//s1能和s3匹配就递归一次,返回值为1就接着返回,因为返回1表示的就是找到了对的路了
    if(j<l2&&s2[j]==s3[k]&&dfs(i,j+1,k+1))return 1;	//s2能和s3匹配也递归一次
    return 0;
}
int main (void)
{
    int n,i,j,k=1;
    cin>>n;
    while(n--&&cin>>s1>>s2>>s3)
    {
        l1=strlen(s1);
        l2=strlen(s2);
        for(i=0;i<222;i++)	//初始化标记数组
        for(j=0;j<222;j++)
        visit[i][j]=0;
        cout<<"Data set "<<k++<<": ";
        if(dfs(0,0,0))cout<<"yes"<<endl;	//直接从三个字符串的第一个开始深搜
        else cout<<"no"<<endl;
    }
    return 0;
}

DP:	//DP的想法就是DP[i][j]代表s1[i]和s2[j]这两个点同ss[i+j]匹配的当前状态
如匹配catrtee,不看其他杂乱的最终就得到这样个图(实际上还有些数字,因为可能是从中间开始匹配成功的)
    c a t
  0 1 2 0
t 0 0 3 0
r 0 0 4 5
e 0 0 0 6
e 0 0 0 7
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int l1,l2,l3;
char s1[444],s2[444],ss[444];
int main (void)
{
    int i,j,n,m=1,dp[222][222];
    scanf("%d",&n);
    while(n--&&scanf("%s%s%s",s1,s2,ss))
    {
        memset(dp,0,sizeof(dp));
        l1=strlen(s1);
        l2=strlen(s2);
        l3=strlen(ss);
        if(ss[0]==s1[0])dp[1][0]=1;	//如果s1第一个和ss配上就标记初始状态“s1成功一个,s2成功0个”为1
        if(ss[0]==s2[0])dp[0][1]=1;	//同上
        for(i=0;i<=l1;i++)	//有了初始状态之后就进行下面的递归
        for(j=0;j<=l2;j++)
        {
            if(i>0&&s1[i-1]==ss[i+j-1])	//s1没完,就用s1来匹配
            dp[i][j]=max(dp[i][j],dp[i-1][j]+1);	//取当前点的值与由前一个状态递推过来的值的最大值,因为有的从中间开始匹配成功的树值会干扰结果
            if(j>0&&s2[j-1]==ss[i+j-1])
            dp[i][j]=max(dp[i][j],dp[i][j-1]+1);
        }
        printf("Data set %d: ",m++);
        if(dp[l1][l2]==l3)
        cout<<"yes"<<endl;
        else cout<<"no"<<endl;
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值