给定一个M行N列的迷宫图,其中 "0"表示可通路,"1"表示障碍物,无法通行。在迷宫中只允许在水平或上下四个方向的通路上行走,走过的位置不能重复走。
5行8列的迷宫如下:
0 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 0 0
0 1 1 1 0 1 1 0
1 0 0 0 0 0 0 0
则从左上角(1,1)至右下角(5,8)的最短路径为:
1,1--》2,1--》2,2--》2,3--》3,3--》3,4--》3,5--》4,5--》5,5--》5,6--》5,7--》5,8
题目保证每个迷宫最多只有一条最短路径。
请输出该条最短路径,如果不存在任何通路,则输出"NO FOUND".
输入格式:
第一行,输入M和N值,表示迷宫行数和列数。
接着输入M行数值,其中,0表示通路,1表示障碍物。每列数值用空格符间隔。
接下来可能输入多组迷宫数据。
当输入M的值为-1时结束输入。
输出格式:
按行顺序输出路径的每个位置的行数和列数,如 x,y
如果不存在任何路径,则输出"NO FOUND".
每组迷宫寻路结果用换行符间隔。
输入样例:
在这里给出一组迷宫。例如:
8 8
0 0 1 0 0 0 1 0
0 0 1 0 0 0 1 0
0 0 0 0 1 1 0 0
0 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 0 0
0 1 1 1 0 1 1 0
1 0 0 0 0 0 0 0
4 4
0 0 1 0
0 0 0 0
0 0 1 1
0 1 0 0
-1 -1
输出样例:
在这里给出相应的输出。例如:
1,1
2,1
3,1
4,1
5,1
5,2
5,3
6,3
6,4
6,5
7,5
8,5
8,6
8,7
8,8
NO FOUND
一些思考:
①知道迷宫寻路的走路思路:
其解法的核心思想非常简单:右手原理。
从起点出发一直往里走,遇到岔路口就做一个节点记录,然后利用右手原理,一直优先选择右边的路线。
只要还能往里走,继续推进前行,直到走不下去碰壁为止,于是沿着路线返回最近的上一个节点,
选择还没有被探索过的路线进行探索,直到所有的可能性都被探索到为止。
②队列包含的数据有哪些,初始化,满的情况判断好
③存迷宫数据要用动态分配空间的二维数组,便于传入函数中。
④队头顺序输出
代码演示:
#include<stdio.h>
#include<stdlib.h>
typedef struct{
int x,y;
int right,down;
}position;
typedef struct{
position *p;
int rear,front;
}SqQueue;
/*下面/**/为如果用入队函数的表示
void EnQueue(SqQueue *Q,int s1,int s2){
Q->p[Q->front].x = s1;
Q->p[Q->front].y = s2;
Q->p[Q->front].down = Q->p[Q->front].right = 1;
Q->front++;
}
*/
int progress(SqQueue *Q,int **a,int m,int n){
int cur_x = Q->p[Q->front-1].x; // 当前所处x的位置
int cur_y = Q->p[Q->front-1].y;
int cur_r = Q->p[Q->front-1].right;//当前能走的方向情况
int cur_d = Q->p[Q->front-1].down;
if(cur_r!=0 && cur_y!= n && a[cur_x][cur_y+1] == 0){//右边没走过且能走
Q->p[Q->front].x = cur_x;
Q->p[Q->front].y = cur_y+1;
Q->p[Q->front].down = Q->p[Q->front].right = 1;
Q->p[Q->front-1].right = 0;
Q->front++;
/*上述五步如果用入队函数上述可改写为
EnQueue(&(*Q),cur_x,cur_y+1);
Q->p[Q->front-2].right = 0;
*/
return 1;
}else if(cur_d!=0&& cur_x!=m && a[cur_x+1][cur_y]==0){//下面没走过且能走
Q->p[Q->front].x = cur_x+1;
Q->p[Q->front].y = cur_y;
Q->p[Q->front].down = Q->p[Q->front].right = 1;
Q->p[Q->front-1].down = 0;
Q->front++;
/*上述五步如果用入队函数上述可改写为
EnQueue(&(*Q),cur_x+1,cur_y);
Q->p[Q->front-2].down = 0;
*/
return 1;
}else if(Q->front!=1){//右下都不能走且队列没有退到只剩起点,可以退回。
Q->front--;
return 1;
}
return 0;
}
void print(SqQueue *Q){
while(Q->rear!=Q->front){
int cur_x = Q->p[Q->rear].x;
int cur_y = Q->p[Q->rear].y;
printf("%d,%d\n",cur_x,cur_y);
Q->rear++;
}
}
int main()
{
//定义两个变量m,n
int m,n;
scanf("%d%d",&m,&n);
while(m!=-1&&n!=-1){ // 外部循环
int **a = (int**)malloc(sizeof(int*)*(m+1));
for(int i = 1;i<=m;i++){
a[i] = (int *)malloc(sizeof(int)*(n+1));
}//不用0行0列
for(int i = 1;i<=m;i++){
for(int j = 1;j<=n;j++)
scanf("%d",&a[i][j]);
}//存迷宫数据
SqQueue Q;
Q.p = (position*)malloc(sizeof(position)*(m+n-1));//队列长度最长15
Q.rear = Q.front = 0;
Q.p[Q.front].x = Q.p[Q.front].y = 1;//存起始位置
Q.front++;
Q.p[0].down = Q.p[0].right = 1;//1表示还没走过的方向
/*如果用入队函数,上述三步可写为
EnQueue(&Q,1,1);
*/
int flag = 1;
while(Q.front!=m+n-1){//还没满。
int re = progress(&Q,a,m,n);//当前队列怎么走函数。
if(re == 0){
flag = 0;
break;
}
}//while走迷宫
if(flag == 0)printf("NO FOUND\n");
else{
print(&Q);
}
free(a);
free(Q.p);
scanf("%d %d",&m,&n);
}//while
return 0;
}