HDU-1501 Zipper DFS+记忆化搜索

171 篇文章 0 订阅
99 篇文章 0 订阅

HDU-1501 Zipper DFS+记忆化搜索

    该题理解为将每一个字母与两个模式串进行匹配,如果不符合则回溯进行匹配。

一个例子:   aaabb  aaaaaacd aaaaaacaaabbd

到组合串第四个字母时,'a' 不能够与A串匹配,于是以状态为A:aaa__, B: a_______,组合串匹配到第五个字母进行递归,......当匹配到组合串的第七个字母 'c'时,该字母与A串以及B串的第四个字母均不能匹配,这时必定将回溯到组合串第三个'a'的匹配过程中,并将第三个 'a' 分配给B串,而这时,A串又会和组合串中的第四个'a' 匹配,接下来,又将以A:aaa__, B: a_______,组合串匹配到第五个字母进行递归过程。注意,这里就产生了跟前面相同的情况了,所以记忆化搜索便是剪枝的最佳方式。

    代码如下:

#include <stdio.h>
#include <string.h>
 
char  w1[205], w2[205], s[410];
 
int  flag1, flag2, len1, len2, lens, hash[205][205];
 
void  DFS( int  x, int  cnt1, int  cnt2 )
{
     if ( x== lens )
     {
         flag2= 1;
         return ;
     }
     if ( hash[cnt1][cnt2] )
     {
         return ;
     }
     hash[cnt1][cnt2]= 1;
     if ( s[x]== w1[cnt1] )
     {
         DFS( x+ 1, cnt1+ 1, cnt2 );
     }
     if ( s[x]== w2[cnt2] )
     {
         DFS( x+ 1, cnt1, cnt2+ 1 );
     }
}
 
int  main(  )
{
     int  T;
     scanf ( "%d" , &T );
     for ( int  t= 1; t<= T; ++t )
     {
         memset ( hash, 0, sizeof ( hash ) );
         flag1= flag2= 0;
         scanf ( "%s%s%s" , w1, w2, s );
         len1= strlen ( w1 );
         len2= strlen ( w2 );
         lens= strlen ( s );
         DFS( 0, 0, 0 );
         printf ( flag2== 1? "Data set %d: yes\n" : "Data set %d: no\n" , t );
     }
     return  0;
}
 
/*
3
cat tree tcraete
cat tree catrtee
cat tree cttaree
 
7
cat tree cttaree
Cat tree tCraete
vvv vvaa vvvaavv
abd hcda hcadbda
cat tree catrtee
bii iiii iiiibii
ddf fdd  fdddfd
*/

Zipper

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


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
 

Source

DP解法:
最优子结构分析:如上例,如果A、B可以组成C,那么,C最后一个字母e,必定是 A 或 C 的最后一个字母组成。
C去除除最后一位,就变成是否可以求出 A-1和B 或者 A与B-1 与 是否可以构成 C-1。。。
状态转移方程: 用f[i][j] 表示 表示A前 i 为 和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]))


[cpp]  view plain copy
  1. #include<stdio.h>  
  2. #include<string.h>  
  3.   
  4. char a[201],b[201],c[402];  
  5. int la,lb,lc;  
  6. int dp[201][201];  
  7.   
  8. int main()  
  9. {  
  10.     int ncase;  
  11.     scanf("%d",&ncase);  
  12.     for(int n=1; n<=ncase; n++) {  
  13.   
  14.         a[0]='p';  
  15.         b[0]='p';  
  16.         c[0]='p';  
  17.   
  18.         scanf("%s%s%s",a+1,b+1,c+1);  
  19.   
  20.         la=strlen(a);  
  21.         lb=strlen(b);  
  22.         lc=strlen(c);  
  23.   
  24.         la-=1;  
  25.         lb-=1;  
  26.   
  27.         //处理边界  
  28.         for (int i=1; i<=la; i++)  
  29.             if (a[i]==c[i]) dp[i][0]=1;   
  30.   
  31.         for (int i=1; i<=lb; i++)  
  32.             if (b[i]==c[i]) dp[0][i]=1;  
  33.         //DP  
  34.         for (int i=1; i<=la; i++)  
  35.             for (int j=1; j<=lb; j++)  
  36.                 dp[i][j]= (dp[i-1][j]&&(a[i]==c[i+j]))||(dp[i][j-1]&&(b[j]==c[i+j]));  
  37.   
  38.         printf("Data set %d: ",n);  
  39.         if (dp[la][lb]==1) printf("yes\n");  
  40.         else printf("no\n");  
  41.     }  
  42.     return 0;  
  43. }  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值