C的迷宫问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C的迷宫问题相关的知识,希望对你有一定的参考价值。

要求编写queue.h,maze.c,queue.c
这里有部分maze.c:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#define MAX_ROWS 300
#define MAX_COLS 300
int main(void)


return 0;


这是迷宫图:
21 21
*********************
* * *
* ******* *** * *** *
* * * * * *
***** * ********* * *
* * * * * *
* * *** * *** *******
* * * * * *
* ******* * ******* *
* * * * *
* ********* * * * * *
* * * * * * *
*** *** * *** * *** *
* * * * * *
* ******* * *** * ***
* * * * * *
* *** * ********* * *
* * * * * * *
* ********* * * *** *
* * * *
*********************
只要从左上角,到右下角,不需要入口和出口
(谁作出来再给30分)
只要求读迷宫,画路,不要画迷宫(迷宫如图所给).
整个顺序为先queue.h,然后maze.c.当跑maze.c的时候,自动跳到queue.c(所有有关函数的文件),再回到maze.c,整个maze.c完了,路也就自然而然出现了.(一定要有路,也就是说怎么跑的)
那个迷宫图"*"代表墙," "(空格)代表路.
老师说降低难度,所以不用入口和出口.

参考技术A 1.回溯算法

7. 迷宫问题
给一个20×20的迷宫、起点坐标和终点坐标,问从起点是否能到达终点。
输入数据:’.’表示空格;’X’表示墙。
程序如下:
#include <stdio.h>
#include <math.h>
void search(int,int);
int canplace(int,int);
void readdata(); //读入数据
void printresult(); //打印结果
int a[20][20]; //a数组存放迷宫
int s,t;
int main()

int row, col;
readdata();
row=s/20;
col=s%20;
search(row,col); //递归搜索
printresult();

void search(int row, int col)

int r,c;
a[row][col]=1;
r=row; //左
c=col-1;
if(canplace(r,c)) //判断(r,c)位置是否已经走过
search(r,c); //递归搜索(r,c)
r=row+1; //下
c=col;
if(canplace(r,c)) //判断(r,c)位置是否已经走过
search(r,c); //递归搜索(r,c)
r=row; //右
c=col+1;
if(canplace(r,c)) //判断(r,c)位置是否已经走过
search(r,c); //递归搜索(r,c)
r=row-1; //上
c=col;
if(canplace(r,c)) //判断(r,c)位置是否已经走过
search(r,c); //递归搜索(r,c)

void printresult()

int i,j;
for(i=0;i<20;i++)

for(j=0;j<20;j++)
printf("%3d",a[i][j]);
printf("\n");


void readdata()

int i,j;
for(i=0;i<20;i++)

for(j=0;j<20;j++)
scanf("%d",&a[i][j]);


int canplace(int row, int col)

if(row>=0&&row<20&&col>=0&&col<20&&a[row][col]==0)
return 1;
else
return 0;


2.搜索算法

如下图12×12方格图,找出一条自入口(2,9)到出口(11,8)的最短路径。

抱歉,图案粘贴不上

本题给出完整的程序和一组测试数据。状态:老鼠所在的行、列。程序如下:
#include<stdio.h>
void readdata(); //读入数据
void init(); //初始化
int search(); //广搜,并在每一个可到达的每一个空格出填上最小步数
int emptyopen(); //判栈是否为空:空:1;非空:0。
int takeoutofopen(); //从栈中取出一个元素,并把该元素从栈中删除
int canmoveto(int,int,int*,int*,int); //判能否移动到该方向,并带回坐标(r,c)
int isaim(int row, int col); //判断该点是否是目标
int used(int,int); //判断该点是否已经走过
void addtoopen(int,int); //把该点加入到open表
int a[12][12]; //a存放迷宫,0表示空格,-2表示墙。
//广搜时,未找到目标以前到达的空格,填上到达该点的最小步数
int n; //n为迷宫边长,注:若大于12,必须修改一些参数,如a的大小
int open[20],head,tail,openlen=20; //open表
int s,t; //起点和终点
int main()

int number;
readdata(); //读取数据
init(); //初始化
number=search(); //广搜并返回最小步数
printf("%d",number); //打印结果

int search()

int u, row, col, r, c, i, num;
while(!emptyopen()) //当栈非空

u=takeoutofopen(); //从栈中取出一个元素,并把该元素从栈中删除
row=u/n; //计算该点的坐标
col=u%n;
num=a[row][col]; //取得该点的步数
for(i=0;i<4;i++)

if(canmoveto(row,col,&r,&c,i)) //判能否移动到该方向,并带回坐标(r,c)

if(isaim(r,c)) //如果是目标结点
return(num+1); //返回最小步数
if(!used(r,c)) //如果(r,c)还未到达过

a[r][c]=num+1; //记录该点的最小步数
addtoopen(r,c); //把该点加入到open表





int emptyopen()

if(head==tail)
return(1);
else
return(0);

int takeoutofopen()

int u;
if(head==tail)

printf("errer: stack is empty");
return(-1);

u=open[head++];
head=head%openlen;
return(u);


int canmoveto(int row, int col, int *p, int *q, int direction)

int r,c;
r=row;
c=col;
switch(direction)

case 0: c--; //左
break;
case 1: r++; //下
break;
case 2: c++; //右
break;
case 3: r--; //上

*p=r;
*q=c;
if(r<0||r>=n||c<0||c>=n) //如果越界返回0
return(0);
if(a[r][c]==0) //如果是空格返回1
return(1);
return(0); //其余情况返回0

int isaim(int row, int col)

if(row*n+col==t)
return(1);
else
return(0);

int used(int row, int col)

if(a[row][col]==0) // 0表示空格
return(0);
else
return(1);

void addtoopen(int row, int col)

int u;
u=row*n+col;
open[tail++]= u;
tail=tail%openlen;

void readdata()

int i,j,row,col;
char str[20];
scanf("%d",&n);
scanf("%d%d",&row,&col); //起点坐标
s=row*n+col;
scanf("%d%d",&row,&col); //终点坐标
t=row*n+col;
gets(str);
for(i=0;i<n;i++)

gets(str);
for(j=0;j<n;j++)
if(str[j]=='.')
a[i][j]=0; //0表示空格
else
a[i][j]=-2; //-2表示墙


void init()

head=0;
tail=1;
open[0]=s;

测试数据如下:
12 10 7 1 8
XXXXXXXXXXXX
X......X.XXX
X.X.XX.....X
X.X.XX.XXX.X
X.X.....X..X
X.XXXXXXXXXX
X...X.X....X
X.XXX...XXXX
X.....X....X
XXX.XXXX.X.X
XXXXXXX..XXX
XXXXXXXXXXXX
参考技术B 我不懂你啥要求,你的图我也看不懂,也不知道你什么编译器,我刚才学习栈的时候写了一个,就给你了,如果你也这么做的话,把你的图改成点阵,并且把多设一个外圈,把最外一层置为1,如果你要做界面的话,我不会我就会dos的你自己改:

#include<stdio.h>
#define M 1000 //栈的容量
struct stack

int top; //栈顶
int path[M][2]; //栈的数据
;
struct position //坐标

int x;
int y;
;
int isOnlyOne(struct stack *p); //判断栈是只剩下一个元素
void push(struct stack *p,int x,int y); //将x,y压入栈
void pop(struct stack *p); //出栈
void display(struct stack *p); //遍历栈
int findPath(int (*a)[10],struct stack *p); //判断路径
int east(struct position temp,int (*a)[10]); //返回当前位置东边的值
int sorth(struct position temp,int (*a)[10]); //返回当前位置南边的值
int west(struct position temp,int (*a)[10]); //返回当前位置西边的值
int north(struct position temp,int (*a)[10]); //返回当前位置北边的值
void moveEast(struct position *p); //向东方移动
void moveSorth(struct position *p); //向南方移动
void moveWest(struct position *p); //向西方移动
void moveNorth(struct position *p); //向北方移动

void main()

struct stack st;
struct stack *p=&st; //定义一个栈的指针
int a[10][10]=1,1,1,1,1,1,1,1,1,1, //创建一个迷宫原型
1,0,0,1,0,0,0,1,0,1, //为方便起见,外圈设为1
1,1,0,1,0,0,0,1,0,1, //0代表有路,1代表障碍物
1,0,0,0,1,1,1,0,0,1, //a[1][1]为入口
1,1,1,0,0,0,0,0,1,1, //a[8][8]为出口
1,0,0,0,1,0,1,0,1,1,
1,0,1,0,0,0,1,0,0,1,
1,0,1,1,1,0,1,1,0,1,
1,1,0,0,0,0,0,1,0,1,
1,1,1,1,1,1,1,1,1,1;
p->top=0; //栈顶初始化为0

if(findPath(a,p)==1) //找到一条路径

printf("找到了一条路径:\n");
display(p); //遍历栈输出沿路的坐标

else //没有路

printf("找不到路径\n");



int isOnlyOne(struct stack *p) //判断栈是否就剩一个元素

if(p->top==1)
return 1;
else
return 0;


void push(struct stack *p,int x,int y) //将x,y压入栈,栈顶指针上移动

p->path[p->top][0]=x;
p->path[p->top][1]=y;
p->top++;

void pop(struct stack *p) //出栈,栈顶指针下移

p->top--;

void display(struct stack *p) //遍历栈

int i;
for(i=0;i<p->top;i++)

printf("x:%d\ty:%d\n",p->path[i][0],p->path[i][1]);


int east(struct position temp,int (*a)[10]) //返回当前位置东边的值

temp.x++;
return a[temp.x][temp.y];

int sorth(struct position temp,int (*a)[10]) //返回当前位置南边的值

temp.y++;
return a[temp.x][temp.y];

int west(struct position temp,int (*a)[10]) //返回当前位置西边的值

temp.x--;
return a[temp.x][temp.y];

int north(struct position temp,int (*a)[10]) //返回当前位置北边的值

temp.y--;
return a[temp.x][temp.y];

void moveEast(struct position *p) //向东方移动

p->x++;

void moveSorth(struct position *p) //向南方移动

p->y++;

void moveWest(struct position *p) //向西方移动

p->x--;

void moveNorth(struct position *p) //向北方移动

p->y--;

int findPath(int (*a)[10],struct stack *p) //寻找路径

struct position temp;
temp.x=temp.y=1; //迷宫入口(1,1)
a[1][1]=1; //将迷宫入口封死
while(temp.x!=8||temp.y!=8) //(8,8)时为出口退出循环

if(east(temp,a)==0) //东边有路

push(p,temp.x,temp.y); //将当前坐标存入栈
moveEast(&temp); //向东移动
a[temp.x][temp.y]=1; //将移动后位置封死防止再次移动到这里

else if(sorth(temp,a)==0) //南边有路

push(p,temp.x,temp.y);
moveSorth(&temp);
a[temp.x][temp.y]=1;

else if(west(temp,a)==0) //西边有路

push(p,temp.x,temp.y);
moveWest(&temp);
a[temp.x][temp.y]=1;

else if(north(temp,a)==0) //北边有路

push(p,temp.x,temp.y);
moveNorth(&temp);
a[temp.x][temp.y]=1;

else //东西南北都没路

if(!isOnlyOne(p))

pop(p); //出栈
temp.x=p->path[p->top-1][0]; //将当前栈顶坐标赋值给x,y
temp.y=p->path[p->top-1][1];

else //只剩下栈的入口了

return 0; //不存在路径



return 1;

本回答被提问者采纳
参考技术C 不懂

C语言 栈 迷宫 的一个疑问

if(Pass(curpos))
...
Push(S,e);
...
if(!StackEmpty(S))
Pop(S,e); curstep--;
...

如果下一步 未通过pass函数
即是未入栈,为何还要出栈,这样不是让上一个入的栈出栈了吗?
求高手解答,谢谢!

全部程序分几个文件,看清楚了,每段程序放入一个文件,每段程序前面都有文件名: //stackoperation.cpp Status InitStack(SqStack &S) //构造一个空栈S S.base = (SElemType *)malloc(RANGE*sizeof(SElemType)); if(!S.base) exit(OVERFLOW); //存储分配失败 S.top = S.base; S.stacksize = RANGE; return OK; //Initstack Status Push(SqStack &S,SElemType e) //插入元素e为新的栈顶元素 if(S.top - S.base >= S.stacksize)//栈满,追加存储空间 S.base = (SElemType*)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SElemType)); if(!S.base) exit(OVERFLOW); //存储分配失败 S.top = S.base + S.stacksize; S.stacksize += STACKINCREMENT; *S.top++ = e; return OK; //Push Status Pop(SqStack &S,SElemType &e) /*若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK; 否则返回ERROR*/ if(S.top == S.base) return ERROR; e = * --S.top; return OK; //Pop bool StackEmpty(SqStack S) //判断栈是否为空并返回TURN或FALSE if(S.top == S.base) return TURE; return FALSE; //StackEmpty void PrintStack() SqStack ST; SElemType e; InitStack(ST); do Pop(SqS,e); Push(ST,e); while(!StackEmpty(SqS)); do Pop(ST,e); printf("(%d,%d,%d)",e.seat.i,e.seat.j,e.di); while(!StackEmpty(ST)); //migong.cpp #include "Basetype.h" #include "stackoperation.cpp" #include "Mazeoperation.cpp" void main() char filename[15]; FILE *fp; printf("请输入迷宫数据文件名(长度不超过15个字符):"); scanf("%s",&filename); //如找不到文件,则要求重新输入(最多三次机会) for(int i=0;i<3;i++) if((fp = fopen(filename,"r")) == NULL) printf("不能打开文件,请重新输入文件名(长度不超过15个字符):\n"); scanf("%s",filename); //if break; //for //读取迷宫的行数和列数 int rnum,cnum; fscanf(fp,"%d,%d",&rnum,&cnum); printf("这个迷宫有%d行,%d列\n",rnum,cnum); if(rnum>RANGE-2 || cnum>RANGE-2) printf("迷宫太大,无法求解\n"); return; //判断迷宫的大小是否符合要求 //初始化一个迷宫变量 MazeType maze; for(i=0;i<=rnum+1;i++) for(int j=0;j<=cnum+1;j++) maze.arr[i][j] = '#'; CreatMaze(maze,rnum,cnum,fp);//创建迷宫 fclose(fp);//关闭迷宫文件 //打印当前迷宫 printf("当前迷宫为:\n"); for(i=0;i<=rnum+1;i++) for(int j=0;j<=cnum+1;j++) printf("%c",maze.arr[i][j]); printf("\n"); printf("其中'#'表示障碍,外围一圈'#'为围墙\n"); //读取入口及出口位置 PosType startp,endp; printf("请输入入口位置(两数中间以逗号相隔):"); scanf("%d,%d",&startp.i,&startp.j); printf("请输入出口位置(两数中间以逗号相隔):"); scanf("%d,%d",&endp.i,&endp.j); if(MazePath(maze,startp,endp)) PrintMaze(maze,rnum,cnum);//将求解的迷宫输出到文件保存,并打印到屏幕 PrintStack();//如果存在路径则打印之 else printf("此迷宫不存在路径\n"); //main //Mazeoperation.cpp bool Pass(MazeType maze,PosType curpos) //判断当前位置是否可通,并返回值 switch(char ch = maze.arr[curpos.i][curpos.j]) case' ': return(FALSE); case'#': case'@': case'*': return(TURE); default: printf("迷宫中第%d行,第%d列出现不明字符%c\n", curpos.i,curpos.j,ch);exit(0); //switch //pass void FootPrint(MazeType &maze,PosType curpos) maze.arr[curpos.i][curpos.j] = '*'; //FootPrint void MarkPrint(MazeType &maze,PosType curpos) maze.arr[curpos.i][curpos.j] = '@'; //MarkPrint void NextPos(PosType &curpos,int di) switch(di) case 1: curpos.j++;break; case 2: curpos.i++;break; case 3: curpos.j--;break; case 4: curpos.i--;break; default: printf("当前方向%d无效\n",di); exit(0); //switch //NextPos bool MazePath(MazeType &maze,PosType start,PosType end) SElemType e; InitStack(SqS); PosType curpos = start; int curstep = 1; do if(!Pass(maze,curpos)) FootPrint(maze,curpos); e.order = curstep; e.seat.i = curpos.i;e.seat.j = curpos.j; e.di = 1; Push(SqS,e); if(curpos.i == end.i && curpos.j == end.j) return(TURE); NextPos(curpos,1); curstep++; //if else if(!StackEmpty(SqS)) Pop(SqS,e); while(e.di == 4 && !StackEmpty(SqS)) MarkPrint(maze,e.seat); Pop(SqS,e); //while if(e.di<4) e.di++; Push(SqS,e); NextPos(e.seat,e.di); curpos.i = e.seat.i;curpos.j = e.seat.j; //if //if //else while(!StackEmpty(SqS)); return(FALSE); //Mazepath void CreatMaze(MazeType &maze,int row,int col,FILE *fp) //建立迷宫 char ch = fgetc(fp); for(int i=1;i<=row;i++) for(int j=1;j<=col;j++) switch( ch = fgetc(fp)) case'0': maze.arr[i][j]=' ';break; case'1': maze.arr[i][j]='#';break; default: printf("迷宫第%d行第%d列数据为%c有错误",i,j,ch);exit(0); //switch //for fseek(fp,2,1); //for fclose(fp); //CreatMaze void PrintMaze(MazeType maze,int row,int col) //打印结果并输出到文件保存 FILE *out; if((out = fopen("outfile","w"))==NULL) printf("不能打开文件\n"); exit(0); //if for(int i=0;i<=row+1;i++) for(int j=0;j<=col+1;j++) fputc(maze.arr[i][j],out); printf("%c",maze.arr[i][j]); printf("\n"); printf("其中'*'号代表路径,'#'代表障碍,'@'代表死胡同\n"); fclose(out);//关闭文件 //Basetype.h #include <stdio.h> #include "stdlib.h" #define RANGE 30 //栈的存储空间初始分配量, //以及用来存放迷宫的字符数组的最大维数 #define TURE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define OVERFLOW -1 #define STACKINCREMENT 5 //栈的存储空间分配增量 typedef struct int i; //行坐标 int j; //列坐标 PosType; //迷宫中坐标位置类型 //栈的定义 typedef struct int order; //通道块在路径上的“方向” PosType seat; //通道块在迷宫中的“坐标位置” int di; //从此通道块走向下一通道块的“方向” SElemType; //栈的元素类型 typedef struct SElemType *base; //栈底指针 SElemType *top; //栈顶指针 int stacksize; //当前已分配的存储空间,以元素为单位 SqStack; //迷宫的定义 typedef struct int m,n; char arr[RANGE][RANGE]; MazeType; typedef int Status; SqStack SqS; //定义一个栈~ 参考技术A 下一步,未通过pass函数说明,这条路径是不可行的,是一个死胡同。
所以就出栈,这是回溯法啊。
当前入栈的位置是到达不了终点的,所以就出栈。返回上一位置,寻找不同路径。本回答被提问者采纳
参考技术B 是这样的
如果Pass返回值=false 代表不通过,则需要退一格 也就是退栈一次pop(),再判断Pass
不知道你的问题在哪里追问

可既然未通过,那么就不会执行NextPos函数了,就是在原地保持不动啊,退一格不是退回上一个位置了?

追答

你的Pass函数只判单方向吗 还是判断该位置是不是死路

贴一些你想问问题的代码段

追问

代码是对的,能实现,但是我对它的实现过程有些不理解
我就是问
当下一个位置不能通过Pass函数时,那么此时栈里面的元素仍然是原来的元素,没有增加。那么进入else,既然未增加元素,为何还要Push?这样不是把上一个元素出栈了吗?

以上是关于C的迷宫问题的主要内容,如果未能解决你的问题,请参考以下文章

C语言 栈 迷宫 的一个疑问

c语言,用二维数组解决迷宫问题。来段完整的代码吧。

Python 解决一个简单的迷宫问题 在线等

C语言数据结构实现:迷宫问题的通用解法

问题 C: 小灰才不走迷宫

问题 C: 小灰才不走迷宫