[poj3984]

来源:互联网 发布:java cookie 编辑:程序博客网 时间:2024/04/28 19:42

原文出处:http://www.cnblogs.com/shuaiwhu/archive/2012/06/22/2557907.html


迷宫问题

Description
定义一个二维数组: 
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到 
右下角的最短路线。

Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output
左上角到右下角的最短路径,格式如样例所示。

Sample Input
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

 

解决方案:

对于这题,我们可以把它maze数组转化为一个图,不能通过的话,即两点之间无路径,然后利用Dijkstra算法寻找S点到T点的最短路径。

Dijkstra算法可参考维基百科迪科斯彻算法,其核心代码如下:

复制代码
 1 function Dijkstra(G, w, s) 2      for each vertex v in V[G]                        // 初始化 3            d[v] := infinity                           // 将各点的已知最短距离先设置成无穷大 4            previous[v] := undefined                   // 各点的已知最短路径上的前趋都未知 5      d[s] := 0                                        // 因为出发点到出发点间不需移动任何距离,所以可以直接将s到s的最小距离设为0 6      S := empty set 7      Q := set of all vertices 8      while Q is not an empty set                      // Dijkstra演算法主體 9            u := Extract_Min(Q)10            S.append(u)11            for each edge outgoing from u as (u,v)12                   if d[v] > d[u] + w(u,v)             // 拓展边(u,v)。w(u,v)为从u到v的路径长度。13                         d[v] := d[u] + w(u,v)         // 更新路径长度到更小的那个和值。14                         previous[v] := u              // 记录前趋顶点
复制代码

对于上图,我们的算法可以大大简化,因为每条路径的权重都相等,由于Dijkstra是按照广度优先搜索来进行遍历的,因而在我们这,先到达这个点的路径即为最短路径(这里对照上图,在纸上画一画就可以体会到)。

对于第9行的 u := Extract_Min(Q) ,我们就用一个队列来表示Q,因为先进来的点的距离不会大于后进来的点,每次从队列头部取出元素,效果与Extract_Min(Q)一样。

代码如下:

复制代码
 1 #include <stdio.h> 2 #include <string.h> 3  4 #define N 5 5  6 void print(int value, int prev[N*N]) 7 { 8     if (value >= 0) 9     {10         int x = value/N;11         int y = value%N;12         print(prev[value], prev);13         printf("(%d, %d)\n", x, y);14     }15 }16 17 void solve(int maze[N][N])18 {19     int visited[N][N];//是否被访问了20     memset(visited, 0, sizeof(visited));//初始化为021 22     int offset[N-1][2] = {23         {1, 0},//向上24         {-1, 0},//向下25         {0, -1},//向左26         {0, 1}//向右27     };28 29     int queue[N*N];//队列30     int front = 0;//头指针31     int rear = 0;//尾指针32 33     int x = 0;//起点x坐标34     int y = 0;//起点y坐标35     queue[++rear] = 0;//向队列添加第一个点,即起始点36     visited[x][y] = 1;//0结点被访问过37 38     int prev[N*N];//保留每个点的前结点39     memset(prev, -1, sizeof(prev));//初始化为-140     prev[0] = -1;//0的前结点为-141 42     while (front <= rear)43     {44         int i;45         int newx;46         int newy;47         front++;//相当于弹出了一个结点48         x = queue[front]/N;49         y = queue[front]%N;50 51         for (i = 0; i < N - 1; i++)52         {53             newx = x + offset[i][0];//偏移之后的x坐标54             newy = y + offset[i][1];//偏移之后的y坐标55             if (newx >= 0 && newx < N && newy >= 0 && newy < N && !visited[newx][newy] && !maze[newx][newy])56             {57                 rear = (rear + 1)%(N*N);58                 queue[rear] = newx*N + newy;59                 prev[newx*N + newy] = x*N + y;60                 visited[newx][newy] = 1;61             }62         }63     }64     print(N*N - 1, prev);65 }66 67 int main()68 {69     int maze[N][N];70     int i = 0;71     int j = 0;72     while (scanf("%d", &maze[i][j++]) != EOF)73     {74         if (j == 5)75         {76             i++;77             j = 0;78         }79         if (i == 5)80         {81             solve(maze);82             i = 0;83         }84     }85     return 0;86 }
复制代码
0 0
原创粉丝点击