双向BFS(转)

(转)

双向BFS(http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx

如果目标也已知的话,用双向BFS能很大提高速度

单向时,是 b^len的扩展。

双向的话,2*b^(len/2)  快了很多,特别是分支因子b较大时

至于实现上,网上有些做法是用两个队列,交替节点搜索 ×,如下面的伪代码:
    while(!empty()){

扩展正向一个节点

遇到反向已经扩展的return

扩展反向一个节点

遇到正向已经扩展的return

}

但这种做法是有问题的,如下面的图:

求S-T的最短路,交替节点搜索(一次正向节点,一次反向节点)时

Step 1 : S –> 1 , 2

Step 2 : T –> 3 , 4

Step 3 : 1 –> 5

Step 4 : 3 –> 5   返回最短路为4,错误的,事实是3,S-2-4-T

我想,正确做法的是交替逐层搜索,保证了不会先遇到非最优解就跳出,而是检查完该层所有节点,得到最优值
也即如果该层搜索遇到了对方已经访问过的,那么已经搜索过的层数就是答案了,可以跳出了,以后不会更优的了。
当某一边队列空时就无解了。

优化:提供速度的关键在于使状态扩展得少一些,所以优先选择队列长度较少的去扩展,保持两边队列长度平衡。这比较适合于两边的扩展情况不同时,一边扩展得快,一边扩展得慢。如果两边扩展情况一样时,加了后效果不大,不过加了也没事。

无向图时,两边扩展情况类似。有向图时,注意反向的扩展是反过来的 x->y(如NOIP2002G2字串变换)

【2002提高】字串变换【2002提高】字串变换

Time Limit:10000MS  Memory Limit:65536K
Total Submit:28 Accepted:3 
Case Time Limit:1000MS

Description

[问题描述]: 
  已知有两个字串 A$, B$ 及一组字串变换的规则(至多6个规则): 
     A1$ -> B1$ 
     A2$ -> B2$ 
  规则的含义为:在 A$中的子串 A1$ 可以变换为 B1$、A2$ 可以变换为 B2$ …。 
    例如:A$=‘abcd‘ B$=‘xyz‘ 
  变换规则为: 
    ‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’

  则此时,A$ 可以经过一系列的变换变为 B$,其变换的过程为: 
   ‘abcd’->‘xud’->‘xy’->‘xyz’

  共进行了三次变换,使得 A$ 变换为B$。

Input

  A$ B$ 
  A1$ B1$ \ 
  A2$ B2$ |-> 变换规则 
  ... ... / 
  所有字符串长度的上限为 20。

Output

  若在 10 步(包含 10步)以内能将 A$ 变换为 B$ ,则输出最少的变换步数;否则输出"NO ANSWER!"

Sample Input

  abcd xyz
  abc xu
  ud y
  y yz

Sample Output

  3

Source

xinyue摘自NOIP2002提高组

转自:http://www.cppblog.com/xiongnanbin/articles/97899.html

分析:
双向BFS:
所谓双向搜索指的是搜索沿两个方向同时进行:
1.正向搜索:从初始结点向目标结点方向搜索。
2.逆向搜索:从目标结点向初始结点方向搜索。
当两个方向的搜索生成同一子结点时终止此搜索过程。

双向搜索通常有两种方法:
1. 两个方向交替扩展。
2. 选择结点个数较少的那个方向先扩展。
方法2克服了两方向结点的生成速度不平衡的状态,明显提高了效率。

[cpp] view plaincopyprint?

  1. #include<iostream>
  2. using namespace std;
  3. struct node
  4. {
  5. char s[30];
  6. int dep;
  7. } list1[5010],list2[5010];
  8. char a[7][30],b[7][30];
  9. int n;
  10. bool check(char *s1,char *s2)
  11. {
  12. if (strlen(s1)!=strlen(s2)) return false;
  13. for (int i=0;i<strlen(s1);i++)
  14. if (s1[i]!=s2[i]) return false;
  15. return true;
  16. }
  17. bool pan1(char *s,int i,int x)
  18. {
  19. for (int j=i;j<i+strlen(a[x]);j++)
  20. if (s[j]!=a[x][j-i]) return false;
  21. return true;
  22. }
  23. bool pan2(char *s,int i,int x)
  24. {
  25. for (int j=i;j<i+strlen(b[x]);j++)
  26. if (s[j]!=b[x][j-i]) return false;
  27. return true;
  28. }
  29. void bfs()
  30. {
  31. int head1,tail1,head2,tail2,i,j,k,l;
  32. head1=tail1=head2=tail2=1;
  33. while (head1<=tail1 && head2<=tail2)
  34. {
  35. if (list1[head1].dep+list2[head2].dep>10)
  36. {
  37. printf("NO ANSWER!\n");
  38. return ;
  39. }
  40. for ( i=0;i<strlen(list1[head1].s);i++)
  41. for ( j=1;j<=n;j++)
  42. if (pan1(list1[head1].s,i,j))
  43. {
  44. tail1++;
  45. for (k=0;k<i;k++) list1[tail1].s[k]=list1[head1].s[k];
  46. for (l=0;l<strlen(b[j]);l++,k++) list1[tail1].s[k]=b[j][l];
  47. for (l=i+strlen(a[j]);l<=strlen(list1[head1].s);l++,k++)
  48. list1[tail1].s[k]=list1[head1].s[l];
  49. list1[tail1].s[k]=‘\0‘;
  50. list1[tail1].dep=list1[head1].dep+1;
  51. for (k=1;k<=tail2;k++)
  52. if (check(list1[tail1].s,list2[k].s))
  53. {
  54. printf("%d\n",list1[tail1].dep+list2[k].dep);
  55. return ;
  56. }
  57. }
  58. for ( i=0;i<strlen(list2[head2].s);i++)
  59. for ( j=1;j<=n;j++)
  60. if (pan2(list2[head2].s,i,j))
  61. {
  62. tail2++;
  63. for (k=0;k<i;k++) list2[tail2].s[k]=list2[head2].s[k];
  64. for ( l=0;l<strlen(a[j]);l++,k++) list2[tail2].s[k]=a[j][l];
  65. for (l=i+strlen(b[j]);l<=strlen(list2[head2].s);l++,k++)
  66. list2[tail2].s[k]=list2[head2].s[l];
  67. list2[tail2].s[k]=‘\0‘;
  68. list2[tail2].dep=list2[head2].dep+1;
  69. for (k=1;k<=tail1;k++)
  70. if (check(list1[k].s,list2[tail2].s))
  71. {
  72. printf("%d\n",list1[k].dep+list2[tail2].dep);
  73. return ;
  74. }
  75. }
  76. head1++; head2++;
  77. }
  78. printf("NO ANSWER!\n");
  79. }
  80. int main()
  81. {
  82. scanf("%s%s",list1[1].s,list2[1].s);
  83. n=1;
  84. while (scanf("%s%s",a[n],b[n])!=EOF) n++;
  85. n--;
  86. list1[1].dep=list2[1].dep=0;
  87. bfs();
  88. return 0;
  89. }
时间: 2024-11-05 22:12:22

双向BFS(转)的相关文章

Hdu1401-Solitaire(双向bfs)

Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left to right respectively.There are four identical pieces on the board. In one move it is allowed to

UVA-1604 Cubic Eight-Puzzle (双向BFS+状态压缩+限制搜索层数)

题目大意:立体的八数码问题,一次操作是滚动一次方块,问从初始状态到目标状态的最少滚动次数. 题目分析:这道题已知初始状态和目标状态,且又状态数目庞大,适宜用双向BFS.每个小方块有6种状态,整个大方格有9*6^8个状态.每个小方块用一位6进制数表示即可. 注意:状态转移时要谨慎,否则会出现意想不到的错误: 这道题的末状态有256(2^8)个,如果对搜索层数不加限制,即使双向BFS也会TLE的,当限制正向搜索15层逆向搜索15层至正向搜索27层反向搜索3层时都能AC(我下面贴出的程序是这样的),其

HDU1195 双向BFS(或BFS)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1195 , 双向BFS或者直接BFS也可以过. 其实这道题只是单向BFS就可以过的,但是为了练算法,所以还是用了双向BFS来写. 算法: 先预处理一下,从1111到9999的所有点进行构图(由于是1~9的,所以除去含有0元素的数字),能进行一次变换变成的数字则表示两点之间连通.然后从初态与目态两个点进行BFS,如果有轨迹重合的就返回路程和. 这里注意双向BFS要一层一层的进行搜索,不然的话会产生错误,

POJ1915Knight Moves(单向BFS + 双向BFS)

题目链接 单向bfs就是水题 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 const int INF = 0x3f3f3f3f; 8 const int Max = 300 + 5; 9 struct Node 10 { 11 int

BFS、双向BFS和A*

BFS.双向BFS和A* Table of Contents 1. BFS 2. 双向BFS 3. A*算法 光说不练是无用的.我们从广为人知的POJ 2243这道题谈起:题目大意:给定一个起点和一个终点.按骑士的走法(走日字),从起点到终点的最少移动多少次 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2RraXJjaGhvZmY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/g

HDU 1043 Eight(双向BFS+康托展开)

http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用双向BFS来做. ①双向BFS 在单向BFS的基础上,多建一个从终止状态开始搜索的队列,当然这个时候需要两个vis[]辅助数组,分别记录两个队列的访问情况,当两个队列相遇时即可终止循环. ②康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[

POJ 1915-Knight Moves (单向BFS &amp;&amp; 双向BFS 比较)

题目链接:Knight Moves 研究了一下双向BFS,不是很难,和普通的BFS一样,双向BFS不过是从 起点和终点同时开始搜索,可减少搜索时间 当两条搜索路线相遇时,结束. 貌似有一年百度的招聘 笔试,就是双向BFS.... 下面,比较一下BFS 和 双向BFS的用时: BFS STL的queue可能会浪费一点时间 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstrin

第六章部分例题 双向bfs邻接表和邻接矩阵实现

Idealpath 双向bfs输出颜色,邻接矩阵实现 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <map> 6 #include <algorithm> 7 8 using namespace std; 9 10 const int maxn=10000; 11 const int inf=1

[NOIP2002]字串变换 T2 双向BFS

题目描述 已知有两个字串  A,B  及一组字串变换的规则(至多6个规则): A1?>B1 A2?>B2 规则的含义为:在  A$中的子串  A1可以变换为可以变换为B1.A2可以变换为可以变换为B2  -. 例如:A==′abcd′B='xyz' 变换规则为: 'abc'-> 'xu' 'ud'-> 'y' 'y'-> 'yz' 则此时,A可以经过一系列的变换变为可以经过一系列的变换变为B,其变换的过程为: 'abcd'-> 'xud'-> 'xy'->

Colour Hash (Uva 704 双向bfs)

Colour Hash Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description This puzzle consists of two wheels. Both wheels can rotate both clock and counter-clockwise. They contain 21 coloured pieces, 10 of which