bfs学习

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 - 1 or + 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

Line 1: Two space-separated integers: N and K

Output

Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.

Sample Input

5 17

Sample Output

4

Hint

The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.
 
题意是:从N点到K点最少的操作数是多少,操作要求为从N点可以到N-1点、N+1点和N*2点这三个点。
代码如下:
 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 }
View Code

 

二维例子:

Knight Moves

A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy. 
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.\n",s,ss,res);
40     }
41 }
View Code

 

三维例子:

胜利大逃亡

Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会. 

魔王住在一个城堡里,城堡是一个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 }
View Code

 

下面给出几个其它的例子:

 

 A strange lift

There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button "UP" , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button "DOWN" , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can't go up high than N,and can't go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button "UP", and you'll go up to the 4 th floor,and if you press the button "DOWN", the lift can't do it, because it can't go down to the -2 th floor,as you know ,the -2 th floor isn't exist. 
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 }
View Code

 

 

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

Input
4 6
X...XX
...XX.
.X..X.
......
1 6
2 2
Output
YES
Input
5 4
.X..
...X
X.X.
....
.XX.
5 3
1 1
Output
NO
Input
4 7
..X.XX.
.XX..X.
X...X..
X......
2 2
1 6
Output
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 }
View Code

 

 

posted @ 2017-04-09 18:39  starry_sky  阅读(355)  评论(0编辑  收藏  举报