bfs(宽度优先搜索),目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
下面给出几个例子。
一维的例子:
Catch That Cow
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
Input
Output
Sample Input
5 17
Sample Output
4
Hint
1 #include <iostream> 2 #include <queue> 3 using namespace std; 4 const int maxn = 1e5+10; 5 int n, k, vis[maxn*2]; 6 7 struct Nod{ 8 int x, step; 9 }pos,q; 10 queue<Nod>que; 11 12 void Push(int x,int step){ 13 q.x = x; 14 vis[x] = 1; 15 q.step = step + 1; 16 que.push(q); 17 } 18 19 int bfs(int n, int k){ 20 pos.x = n,pos.step = 0; 21 vis[n] = 1; 22 que.push(pos); 23 while(que.size()){ 24 pos = que.front(); 25 que.pop(); 26 if(pos.x == k) return pos.step; 27 int x = pos.x -1; 28 if(vis[x] == 0 && x >= 0 && x < maxn){ 29 Push(x,pos.step); 30 } 31 x = pos.x + 1; 32 if(vis[x] == 0 && x >= 0 && x < maxn){ 33 Push(x,pos.step); 34 } 35 x = 2 * pos.x; 36 if(vis[x] == 0 && x >= 0 && x < maxn){ 37 Push(x,pos.step); 38 } 39 } 40 return -1; 41 } 42 int main(){ 43 cin >> n >> k; 44 cout << bfs(n,k)<< endl; 45 }
二维例子:
Knight Moves
Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.
Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
InputThe input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.
OutputFor each test case, print one line saying "To get from xx to yy takes n knight moves.".
Sample Input
e2 e4 a1 b2 b2 c3 a1 h8 a1 h7 h8 a1 b1 c3 f6 f6
Sample Output
To get from e2 to e4 takes 2 knight moves. To get from a1 to b2 takes 4 knight moves. To get from b2 to c3 takes 2 knight moves. To get from a1 to h8 takes 6 knight moves. To get from a1 to h7 takes 5 knight moves. To get from h8 to a1 takes 6 knight moves. To get from b1 to c3 takes 1 knight moves. To get from f6 to f6 takes 0 knight moves.
题意是:在二维坐标中a-h和1-8这份8*8的坐标中,给点起点和终点,求从起点到终点最少需要多少步,每次走的反向按国际象棋中“骑士”的做法,就和中国象棋中的“马”一样。
代码如下:
1 #include <iostream> 2 #include <queue> 3 #include <cstdio> 4 using namespace std; 5 char s[5], ss[5]; 6 int gx, gy, sx, sy; 7 int dis[8][2] = {{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2}}; 8 typedef pair<int, int> P; 9 int d[10][10]; 10 int bfs(){ 11 queue<P> que; 12 for(int i = 0; i < 8; i ++){ 13 for(int j = 0; j < 8; j ++){ 14 d[i][j] = 1e6; 15 } 16 } 17 que.push(P(sx, sy)); 18 d[sx][sy] = 0; 19 while(que.size()){ 20 P p = que.front();que.pop(); 21 if(p.first == gx && p.second == gy) return d[gx][gy]; 22 for(int i = 0; i < 8; i ++){ 23 int nx = p.first + dis[i][0], ny = p.second + dis[i][1]; 24 if(0 <= nx && nx < 8 && 0 <= ny && ny < 8 && d[nx][ny] == 1e6){ 25 d[nx][ny] = d[p.first][p.second] + 1; 26 que.push(P(nx, ny)); 27 } 28 } 29 } 30 return d[gx][gy]; 31 } 32 int main(){ 33 while(cin>>s>>ss){ 34 sx = s[0] - 'a'; 35 sy = s[1] - '1'; 36 gx = ss[0] - 'a'; 37 gy = ss[1] - '1'; 38 int res = bfs(); 39 printf("To get from %s to %s takes %d knight moves. ",s,ss,res); 40 } 41 }
三维例子:
胜利大逃亡
魔王住在一个城堡里,城堡是一个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1.
Input输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙.(如果对输入描述不清楚,可以参考Sample Input中的迷宫描述,它表示的就是上图中的迷宫)
特别注意:本题的测试数据非常大,请使用scanf输入,我不能保证使用cin能不超时.在本OJ上请使用Visual C++提交.
Output对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.
Sample Input
1 3 3 4 20 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 0 0 0 0 1 1 0 0 1 1 0
Sample Output
11
题意就是求从(0,0,0)到(a-1,b-1,c-1)的最少的步数。
代码如下:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 using namespace std; 6 const int INF = 100; 7 const int maxn = 55; 8 int dir[maxn][maxn][maxn]; 9 int a, b, c,t; 10 bool vis[maxn][maxn][maxn]; 11 int dd[6][3] = { 12 {1,0,0}, 13 {-1,0,0}, 14 {0,1,0}, 15 {0,-1,0}, 16 {0,0,1}, 17 {0,0,-1} 18 }; 19 bool jud(int x, int y, int z){ 20 if(x<0|| y<0 || z<0 || x>=a || y>=b || z>=c) return 0; 21 if(vis[x][y][z] || dir[x][y][z])return 0; 22 return 1; 23 } 24 struct Nod{ 25 int x, y, z, step; 26 }pos,p; 27 int bfs(){ 28 queue<Nod> que; 29 pos.x=pos.y=pos.z=pos.step=0; 30 vis[0][0][0] = 1; 31 que.push(pos); 32 while(que.size()){ 33 pos = que.front();que.pop(); 34 if(pos.x == a-1 && pos.y == b-1 && pos.z == c-1)return pos.step; 35 if(pos.step > t) return -1; 36 for(int i = 0; i < 6; i++){ 37 p.x = pos.x + dd[i][0], p.y = pos.y + dd[i][1], p.z = pos.z + dd[i][2]; 38 if(jud(p.x, p.y, p.z)){ 39 p.step = pos.step + 1; 40 vis[p.x][p.y][p.z] = 1; 41 que.push(p); 42 } 43 } 44 } 45 return -1; 46 } 47 void solve(){ 48 scanf("%d%d%d%d",&a,&b,&c,&t); 49 for(int i = 0; i < a; i ++){ 50 for(int j = 0; j < b; j++){ 51 for(int k = 0; k < c; k++){ 52 scanf("%d",&dir[i][j][k]); 53 } 54 } 55 } 56 memset(vis, 0, sizeof(vis)); 57 cout << bfs() << endl; 58 59 } 60 int main(){ 61 int k; 62 cin >> k; 63 while(k--){ 64 solve(); 65 } 66 return 0; 67 }
下面给出几个其它的例子:
A strange lift
Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button "UP" or "DOWN"?
InputThe input consists of several test cases.,Each test case contains two lines.
The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,....kn.
A single 0 indicate the end of the input.OutputFor each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can't reach floor B,printf "-1".Sample Input
5 1 5 3 3 1 2 5 0
Sample Output
3
题意是:N层楼,求从A到B的最少操作数,每栋楼i对应一个Ki,表示从第i层可以到达 i + Ki层或 i - Ki层,到每次到达的楼层会能超过N和小于1。
代码如下:
1 #include <iostream> 2 #include <queue> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 const int maxn = 250; 7 int n, a, b, dis[maxn]; 8 bool vis[maxn<<1]; 9 10 struct Nod{ 11 int x, step; 12 }pos,p; 13 14 int bfs(){ 15 queue<Nod>que; 16 memset(vis, false, sizeof(vis)); 17 pos.x = a, pos.step = 0; 18 vis[a] = 1; 19 que.push(pos); 20 while(que.size()){ 21 pos = que.front(); 22 que.pop(); 23 if(pos.x == b) return pos.step; 24 int x = pos.x + dis[pos.x]; 25 for(int i = -1; i <= 1; i += 2){ 26 p = pos; 27 p.x += i*dis[p.x]; 28 if(0 < p.x && p.x <= n && vis[p.x] == 0){ 29 vis[p.x] = 1; 30 p.step++; 31 que.push(p); 32 } 33 } 34 } 35 return -1; 36 } 37 int main(){ 38 while(~scanf("%d",&n)&&n){ 39 scanf("%d%d",&a,&b); 40 for(int i = 1; i <= n; i ++) scanf("%d",&dis[i]); 41 cout << bfs() << endl; 42 } 43 }
Ice Cave
You play a computer game. Your character stands on some level of a multilevel ice cave. In order to move on forward, you need to descend one level lower and the only way to do this is to fall through the ice.
The level of the cave where you are is a rectangular square grid of n rows and mcolumns. Each cell consists either from intact or from cracked ice. From each cell you can move to cells that are side-adjacent with yours (due to some limitations of the game engine you cannot make jumps on the same place, i.e. jump from a cell to itself). If you move to the cell with cracked ice, then your character falls down through it and if you move to the cell with intact ice, then the ice on this cell becomes cracked.
Let's number the rows with integers from 1 to n from top to bottom and the columns with integers from 1 to m from left to right. Let's denote a cell on the intersection of the r-th row and the c-th column as (r, c).
You are staying in the cell (r1, c1) and this cell is cracked because you've just fallen here from a higher level. You need to fall down through the cell (r2, c2)since the exit to the next level is there. Can you do this?
Input
The first line contains two integers, n and m (1 ≤ n, m ≤ 500) — the number of rows and columns in the cave description.
Each of the next n lines describes the initial state of the level of the cave, each line consists of m characters "." (that is, intact ice) and "X" (cracked ice).
The next line contains two integers, r1 and c1 (1 ≤ r1 ≤ n, 1 ≤ c1 ≤ m) — your initial coordinates. It is guaranteed that the description of the cave contains character 'X' in cell (r1, c1), that is, the ice on the starting cell is initially cracked.
The next line contains two integers r2 and c2 (1 ≤ r2 ≤ n, 1 ≤ c2 ≤ m) — the coordinates of the cell through which you need to fall. The final cell may coincide with the starting one.
Output
If you can reach the destination, print 'YES', otherwise print 'NO'.
Example
4 6
X...XX
...XX.
.X..X.
......
1 6
2 2
YES
5 4
.X..
...X
X.X.
....
.XX.
5 3
1 1
NO
4 7
..X.XX.
.XX..X.
X...X..
X......
2 2
1 6
YES
Note
In the first sample test one possible path is:
After the first visit of cell (2, 2) the ice on it cracks and when you step there for the second time, your character falls through the ice as intended.
题意是:从能否从(r1,c1)到(r2,c2),并从(r2,c2)掉下去,‘.’表示完整的冰,踩两次才会掉下去,‘X’表示破碎的冰,踩一次就会掉下去。
代码如下:
1 #include <iostream> 2 #include <queue> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 const int maxn = 1e3; 7 string s[maxn]; 8 int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1}; 9 int n, m, sx, sy, gx, gy; 10 typedef pair<int, int> P; 11 12 void bfs(){ 13 queue<P> que; 14 que.push(P(sx, sy)); 15 while(que.size()){ 16 P p = que.front(); 17 que.pop(); 18 for(int i = 0; i < 4; i ++){ 19 int nx = p.first + dx[i], ny = p.second + dy[i]; 20 if(0 <= nx && nx < n && 0 <= ny && ny < m){ 21 if(s[nx][ny] == 'X'){ 22 if(nx == gx && ny == gy){ 23 puts("YES"); 24 return; 25 } 26 }else{ 27 s[nx][ny] = 'X'; 28 que.push(P(nx, ny)); 29 } 30 } 31 } 32 } 33 puts("NO"); 34 } 35 36 int main(){ 37 while(~scanf("%d%d",&n,&m)){ 38 for(int i = 0; i < n; i ++) cin >> s[i]; 39 scanf("%d%d%d%d",&sx,&sy,&gx,&gy); 40 sx--;sy--;gx--;gy--; 41 bfs(); 42 } 43 return 0; 44 }