杭电 1501 zipper(典型dfs)

写在前面的:
最近一直在做搜索,这个题目也是DFS一道很典型的题目,一开始想不用搜索做,结果发现思路是错的,大神给了我几组样例之后就只能重拍了。所以开始考虑DFS.一开始没看出来时搜索,所以按自己方法做,但是仔细思考一下还是看出来了。
解题思路如下:
题目要求是给你三个字符串,前两个字符串长度在1--200之间,这说明没有空串。第三个串是前两个字符串的组合,长度等于前两个字符串的长度之和,第三个字符串里面包含前两个字符串的所有字符。题目中的第三个字符串的组成是前两个字符串中的字符打乱顺序组成的,但是这里的顺序和我们认为的也许不一样。如下面这组样例

 

 

  
  
3 cat tree tcraete cat tree catrtee cat tree cttaree
 


 

Sample Output
  
  
Data set 1: yes Data set 2: yes Data set 3: no

 

 

先看第一组样例,也许你就会明白,前两个字符串中字符的顺序在第三个字符串中是不能改变的,也就是说,第三个字符串的构成是把前两个字符串相互穿插得到,但是前两个字符串中的字符顺序不能够打乱。
所以我们很容易想到的就是逐个去比较,这也就用到了DFS的性质,想达到目标有很多步骤,每一个步骤也有多重可能。

题目的要求也是要你在第三个字符串去寻找,看利用前两个字符串中的字符组成后,里面是不是有顺序颠倒的现象,如果有No,否则YES。
我的搜索思路是:
i,j,k分别代表a,b,c串的下标,初始都是0。从c串的第一个字符开始,看看在a,b串对应的顺序中是不是得到匹配,如果都得不到,则证明顺序反了,可以退出。如果一个匹配那就继续在这个找出匹配的字符串中继续搜索,如果没有,则在下一个b串进行搜索。总之,三个字符串的下标都是一个个向后移动的。c串每次比较一个字符,在a,b两个串中当前的顺序所对应的字符都必须找到一个匹配的,如果找不到证明顺序就是反得(因为第三个就是由前两个构成的,你现在对应的第三个字符串的字符你在当前位置前两个字符串所对应的字符找不到的话,那么肯定是,前两个字符串当前位置对应之后的字符跑到了第三个字符串当前的位置,这显然顺序反了,违反题意)。
搜索算法写出来不是很难,难的地方是剪枝的思想。如果你不剪枝,只能TLE。


关于剪枝:
这个剪枝,我觉得应该用记忆化搜索去剪枝。理由是这样的。如果你这条路可行,那么可能是一搜到底直接出答案了。如果不行,那就证明此路不通,而你刚才走过的路肯定是错的,为了避免再走一次你已经知道是错误的路(如果你硬要这样做,那你就去死吧),所以要没走一步,把你所走的那一步标记一下。你本次搜索(如果是失败的)的剪枝
是为了下一次搜索正确的做的准备。因为本次搜索一旦失败,并把走过的定点标记,那么下一次,如果你将要走的这条路已经被标记为错误,那么你肯定就会另寻出路了。
这样可以有效的避免超时,我觉得是一个记忆化搜索的思想。
好啦,思路也不知道讲没讲清楚,没有的话就看代码手算的走几遍,肯定会懂得,我就是这样。

 

最后要提醒大家的是,只要做搜索一定要时刻提醒自己剪枝啊~~~~~~!@!!!!!
PS:饿死了,不行了,下课了就拍了代码写解题报告,饿死了,吃饭去了

 


代码如下:

 

 

 

01  //Zipper //
02  //题目链接:http://acm.hdu.edu.cn/webcontest/contest_showproblem.php?pid=1005&ojid=0&cid=4532//
03  /*自己理解后拍的代码*/
04  #include<stdio.h>
05  #include<string.h>
06  char a [ 202 ],b [ 202 ], c [ 404 ];
07  int fanhui = 0;
08  bool vis [ 205 ][ 205 ] = { 0 };
09  void dfs( int i , int j , int k)
10  {
11      if( c [ k ] == '\0')
12      {
13          fanhui = 1;
14          return;
15      }
16      if( vis [ i ][ j ]|| fanhui)
17      {
18          return ;
19      }
20      vis [ i ][ j ] = 1;
21      if( c [ i ] != '\0' && a [ i ] == c [ k ])
22          dfs( i + 1 , j , k + 1);
23      if( c [ j ] != '\0' &&b [ j ] == c [ k ])
24          dfs( i , j + 1 , k + 1);
25 
26  }
27  int main()
28  {
29      int count = 0;
30      int N;
31      int i , j , k;
32      while( scanf( "%d" , &N) != EOF)
33      {
34          count = 0;
35          while(N --)
36          {
37              memset( vis , 0 , sizeof( vis));
38              fanhui = 0;
39              scanf( "%s%s%s" , a ,b , c);
40              dfs( 0 , 0 , 0);
41              count ++;
42              printf( "Data set %d: %s \n " , count , fanhui ? "yes" : "no");
43          }
44      }
45      return 0;
46  }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值