The Game

Time Limit: 2 Seconds      Memory Limit: 65536 KB

One morning, you wake up and think: ``I am such a good programmer. Why not make some money?'' So you decide to write a computer game.

The game takes place on a rectangular board consisting of w * h squares. Each square might or might not contain a game piece, as shown in the picture.

One important aspect of the game is whether two game pieces can be connected by a path which satisfies the two following properties:

It consists of straight segments, each one being either horizontal or vertical. 

It does not cross any other game pieces. 

(It is allowed that the path leaves the board temporarily.)

The game pieces at (1,3) and at (4, 4) can be connected. The game pieces at (2, 3) and (3, 4) cannot be connected; each path would cross at least one other game piece.

The part of the game you have to write now is the one testing whether two game pieces can be connected according to the rules above.


Input 

The input contains descriptions of several different game situations. The first line of each description contains two integers w and h (1 <= w,h <= 75), the width and the height of the board. The next h lines describe the contents of the board; each of these lines contains exactly w characters: a ``X'' if there is a game piece at this location, and a space if there is no game piece.

Each description is followed by several lines containing four integers x1, y1, x2, y2 each satisfying 1 <= x1,x2 <= w, 1 <= y1,y2 <= h. These are the coordinates of two game pieces. (The upper left corner has the coordinates (1, 1).) These two game pieces will always be different. The list of pairs of game pieces for a board will be terminated by a line containing ``0 0 0 0".

The entire input is terminated by a test case starting with w=h=0. This test case should not be procesed.


Output 

For each board, output the line ``Board #n:'', where n is the number of the board. Then, output one line for each pair of game pieces associated with the board description. Each of these lines has to start with ``Pair m: '', where m is the number of the pair (starting the count with 1 for each board). Follow this by ``ksegments.'', where k is the minimum number of segments for a path connecting the two game pieces, or ``impossible.'', if it is not possible to connect the two game pieces as described above.

Output a blank line after each board.


Sample Input

5 4
XXXXX
X   X
XXX X
 XXX 
2 3 5 3
1 3 4 4
2 3 3 4
0 0 0 0
0 0


Sample Output

Board #1:
Pair 1: 4 segments.
Pair 2: 3 segments.
Pair 3: impossible.

 

  看起来像连连看游戏,但连连看游戏只能有两个拐弯,而这个游戏允许有多个拐弯。很容想到广度优先搜索,只是因为要尽量少拐弯,所以在搜索时沿一个方向,只要能够连的话,就一直连下去即可。(这样难道不会错误吗?)

  (1)数据结构和数据的读取

  使用数组表示举行游戏板: char g[80][80];

  由于连接时,可以暂时离开矩形游戏板,所以矩形游戏板的四周要加大一圈空格。

  (2)BFS实现

    数据结构(自己写的队列)

  用于存储BFS的队列: struct {int x,y;}q[3000];

  存储从起点开始的步数:int steps[80][80];

  需要连接的一对游戏板坐标: int sx,sy,dx,dy;

    与普通广度优先算法的区别

  一般的广度优先搜索算法,只需要向结点的四周搜索就行了,但是本题需要尽可能少的拐弯。这就要求在搜索时,在同一个方向,应该一直往前走。为了做到这一点,只要将当前的坐标增量继续往下加就可以了,一直到不能前进为止。

代码如下:

ZOJ 1148 The Game(BFS)_连连看ZOJ 1148 The Game(BFS)_i++_02
 1 # include<stdio.h>
 2 # include<memory.h>
 3 
 4 //用于BFS的队列
 5 struct
 6 {
 7     int x,y;
 8 } q[3000];
 9 
10 char g[80][80];     //存储矩形游戏板
11 int steps[80][80];  //存储从起点开始的步数
12 int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1}};
13 
14 int main()
15 {
16     int i;
17     int n=1;
18     int sx,sy,dx,dy;
19     int h,w;        //矩形板的宽度和高度
20     while(scanf("%d%d",&w,&h) && (h||w))
21     {
22         getchar();      //读取回车
23         int m=1;
24         for(i=1; i<=h; i++)     //读取游戏板
25             gets(&g[i][1]);
26                 //矩形板四周加空格
27         for(i=0; i<w+2; i++)
28             g[0][i] = g[h+1][i] = ' ';
29         for(i=1; i<=h; i++)
30             g[i][0] = g[i][w+1] = ' ';
31         printf("Board #%d:\n",n++);
32         while(scanf("%d%d%d%d",&sy,&sx,&dy,&dx))
33         {
34             if(!(sx||sy||dx||dy)) break;
35             memset(steps,-1,sizeof(steps));
36             g[sx][sy] = g[dx][dy] = ' ' ;
37             steps[sx][sy] = 0 ;
38             int top=0;          //头结点指针
39             int tail = 0;       //尾结点指针
40             int x0,y0;          //当前结点
41             q[top].x = sx;      //当前结点
42             q[top].y = sy;
43             while(top<=tail && steps[dx][dy] == -1) //队列不为空,且结点没有搜索过
44             {
45                 for(i=0; i<4; i++)
46                 {
47                     x0 = q[top].x + dir[i][0];
48                     y0 = q[top].y + dir[i][1];
49                     //沿着该方向一直搜索
50                     while(x0 >= 0 && x0 <= h+1 && y0 >= 0 &&y0 <= w+1 && g[x0][y0] ==' ' && steps[x0][y0] == -1)
51                     {
52                         //当前结点加入到尾部
53                         tail++;
54                         q[tail].x = x0;
55                         q[tail].y = y0;
56                         //步数加1,注意是相对于top结点加1,即这一条线上的步数相同
57                         steps[x0][y0] = steps[q[top].x][q[top].y] + 1;
58                         //该方向的下一个结点
59                         x0 += dir[i][0];
60                         y0 += dir[i][1];
61                     }
62                 }
63                 top++;
64             }
65             g[sx][sy] = g[dx][dy] = 'X';    //恢复该对游戏板的原先状态,为下一组数据准备
66             printf("Pair %d: ",m++);
67             if(steps[dx][dy]==-1)
68                 printf("impossible.\n");
69             else
70                 printf("%d segments.\n",steps[dx][dy]);
71         }
72         puts("");
73     }
74     return 0;
75 }
View Code

 代码中有两个小知识:gets(&g[i][1]),因为要在第0列添加空格,所以输入的地图应该从第1列开始,这个是取址的意思吧。

  memset可以把数组初始化为-1的

把每一件简单的事情做好,就是不简单;把每一件平凡的事情做好,就是不平凡!相信自己,创造奇迹~~