HDOJ1195 双向BFS //单向也可以过

  1 #include<cstdio>
  2 #include<map>
  3 #include<vector>
  4 #include<stack>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<cstring>
  8 #include<cmath>
  9 #include<queue>
 10 #include<cstdlib>
 11 #define PI acos(-1.0)
 12 using namespace std;
 13 typedef long long ll;
 14 const ll mood=1e9+7;
 15 const double eps=1e-9;
 16 const int N=1e4+10;
 17 const int MAXN=510;
 18 struct node{
 19     string password;
 20     int cnt;
 21     }now,tmp;
 22 string beg,end;
 23 map<string,int>back_vis;
 24 map<string,int>vis;
 25 queue<struct node>q;
 26 queue<struct node>back_q;
 27 int back_bfs(int n)//反向BFS,每次只搜一层,即第n层
 28 {
 29     while(back_q.front().cnt<=n)
 30     {
 31         now=back_q.front();
 32         back_q.pop();
 33         for(int i=0;i<4;i++)
 34         {   //各个位-1\
 35                tmp=now;
 36             if(tmp.password[i]!=‘1‘)
 37                 tmp.password[i]--;
 38             else   tmp.password[i]=‘9‘;
 39             if(vis.find(tmp.password)!=vis.end())//判断是否在正向队列中找到
 40             return tmp.cnt+1+vis[tmp.password];
 41             if(back_vis.find(tmp.password)==back_vis.end())
 42             {
 43                 tmp.cnt++;
 44                 back_q.push(tmp);
 45                 back_vis[tmp.password]=tmp.cnt;
 46             }   //各个位+1
 47             tmp=now;
 48             if(tmp.password[i]!=‘9‘)   tmp.password[i]++;
 49             else   tmp.password[i]=‘1‘;
 50             if(vis.find(tmp.password)!=vis.end())//判断是否在正向队列中找到
 51                 return tmp.cnt+1+vis[tmp.password];
 52             if(back_vis.find(tmp.password)==back_vis.end())
 53             {
 54                 tmp.cnt++;
 55                 back_q.push(tmp);
 56                 back_vis[tmp.password]=tmp.cnt;
 57             }
 58         }
 59         for(int i=0;i<3;i++)
 60         {
 61             tmp=now;
 62             swap(tmp.password[i],tmp.password[i+1]);
 63             if(vis.find(tmp.password)!=vis.end())//判断是否在正向队列中找到   、
 64             return tmp.cnt+1+vis[tmp.password];
 65             if(back_vis.find(tmp.password)==back_vis.end())
 66             {   tmp.cnt++;   back_q.push(tmp);   back_vis[tmp.password]=tmp.cnt;   }
 67         }
 68     }
 69     return -1;
 70 }
 71 int bfs()
 72 {
 73     while(!q.empty())
 74         q.pop();//清空正向BFS的队列
 75     now.password=beg;
 76     now.cnt=0;
 77     q.push(now);
 78     vis[beg]=0;
 79     while(!q.empty())
 80     {
 81         int n=q.front().cnt;
 82         while(q.front().cnt<=n)
 83         {
 84             now=q.front();   q.pop();
 85             for(int i=0;i<4;i++)
 86             {   //各个位-1
 87                 tmp=now;
 88                 if(tmp.password[i]!=‘1‘)
 89                        tmp.password[i]--;
 90                 else   tmp.password[i]=‘9‘;
 91                 if(back_vis.find(tmp.password)!=back_vis.end())//判断是否在反向队列中找到
 92                 return tmp.cnt+1+back_vis[tmp.password];
 93                 if(vis.find(tmp.password)==vis.end())
 94                 {   tmp.cnt++;   q.push(tmp);   vis[tmp.password]=tmp.cnt;   }   //各个位+1
 95                 tmp=now;
 96                 if(tmp.password[i]!=‘9‘)   tmp.password[i]++;
 97                 else   tmp.password[i]=‘1‘;
 98                 if(back_vis.find(tmp.password)!=back_vis.end())//判断是否在反向队列中找到
 99                 return tmp.cnt+1+back_vis[tmp.password];
100                 if(vis.find(tmp.password)==vis.end())
101                 {   tmp.cnt++;   q.push(tmp);   vis[tmp.password]=tmp.cnt;   }
102             }
103             for(int i=0;i<3;i++)
104             {
105                 tmp=now;
106                 swap(tmp.password[i],tmp.password[i+1]);
107                 if(back_vis.find(tmp.password)!=back_vis.end())//判断是否在反向队列中找到
108                 return tmp.cnt+1+back_vis[tmp.password];
109                 if(vis.find(tmp.password)==vis.end())   {
110                     tmp.cnt++;   q.push(tmp);
111                     vis[tmp.password]=tmp.cnt;
112                 }
113             }
114         }
115         int ret=back_bfs(now.cnt);
116         if(ret!=-1)
117             return ret;
118     }
119 }
120 int main(){
121     int t;
122     while(cin>>t)
123     {
124         while(t--)
125         {
126             cin>>beg;
127             cin>>end;
128             vis.clear();//清空map
129             back_vis.clear();//清空map
130             while(!back_q.empty())
131             back_q.pop();//清空反向BFS的队列
132             now.password=end;
133             now.cnt=0;
134             back_q.push(now);
135             back_vis[end]=0;//将反向BFS的起始点入队列标记
136             int ret=bfs();
137             cout<<ret<<endl;
138         }
139     }
140     return 0;
141 }    
时间: 2025-01-01 19:36:06

HDOJ1195 双向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

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

UVa1601 - The Morning after Halloween(单向+双向BFS)

给出一个最大为16×16的迷宫图和至多3个ghost的起始位置和目标位置,求最少经过几轮移动可以使三个ghost都到达目标位置.每轮移动中,每个ghost可以走一步,也可以原地不动,需要注意的是任意两个ghost不能在相同的位置,因此也不能出现任意两个ghost对穿,也就是原来是ab,移动之后是ba.每个迷宫图'#'表示墙,' '表示空地,小写字母表示ghost的起始位置,大写字母表示对应ghost的目标位置,比如'a'应该走到'A'.保证任意2×2的空间内都有一个'#'. 看起来就像是人数多了

HDU1195 双向BFS(或BFS)

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

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[

双向BFS(转)

(转) 双向BFS(http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx) 如果目标也已知的话,用双向BFS能很大提高速度 单向时,是 b^len的扩展. 双向的话,2*b^(len/2)  快了很多,特别是分支因子b较大时 至于实现上,网上有些做法是用两个队列,交替节点搜索 ×,如下面的伪代码:    while(!empty()){ 扩展正向一个节点 遇到反向已经扩展的return 扩展反向一个节点 遇到正向已经扩展的retur

UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS &amp;&amp; 降维 &amp;&amp; 状压)

题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占用同一个位置,也不能在一步之内交换位置.输入保证所有空格连通,所有障碍格也连通,且任何一个2*2子网格中至少有一个障碍格.输出最少的步数.输入保证有解. 分析 :可以将当前所有小鬼的位置作为一个状态,然后模拟小鬼移动BFS拓展出其他可行状态并且顺带记录步数,直到所有的小鬼都到达终点.首先状态如何表示

【HDU3085】nightmare2 双向BFS

对于搜索树分支很多且有明确起点和终点的情况时,可以采用双向搜索来减小搜索树的大小. 对于双向BFS来说,与单向最大的不同是双向BFS需要按层扩展,表示可能到达的区域.而单向BFS则是按照单个节点进行扩展,因为只有当前状态. 代码如下: #include <bits/stdc++.h> using namespace std; const int maxn=810; char mp[maxn][maxn]; int n,m,tot,step,f; struct node{ int x,y; }b

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