第五组 迷宫求解

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第五组成员
题目:迷宫求解
程序:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define maxsize 36
typedef struct lnode{
struct lnode *next;
struct lnode *pre;
int x;
int y;
int stepsum; //表示当前脚步为第几步。

int di;
//用di代表已尝试的脚步方向。

1.2.3.4分别代表未尝试:↑、→、↓、←。

}lnode,*linklist;
//全局变量开始
linklist L,L2,p,q,g;//三个指针pqg满足不同函数临时指针需要
lnode *nowstep,*laststep;
int maze[maxsize+2][maxsize+2];//存储迷宫的数组,+2是为了加围墙。

int m,n;//迷宫行、列数变量
int exitx,exity,entrancex,entrancey;//出入口的坐标:xy分别代表行列.
int finish=0;//走迷宫的最终全局结果。

1有路,-1无路,2出入口重合。

int existL=0;//手动创建迷宫,选择r重新创建迷宫,formatmaze()将格式化各变量。

检测L链表是否存在防止程序崩溃。

int mindistance=0;//存放求出的最短路径的步数。

int autocreat() //默认创建的迷宫函数
{
int i,j,f;
int maze1[10][10]=
{
{0,0,0,0,0,0,0,0,0,0}, //0:代表砖;1:代表通路
{0,1,1,0,1,1,1,0,1,0},
{0,1,1,0,1,1,1,0,1,0},
{0,1,1,1,1,0,0,1,1,0},
{0,1,0,0,0,1,1,1,1,0},
{0,1,1,1,0,1,1,1,1,0},
{0,1,0,1,1,1,0,1,1,0},
{0,1,0,0,0,1,0,0,1,0},
{0,0,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0},
};
//将maze1存储的迷宫复制到maze数组中。

for(i=0;i<10;i++)
for(j=0;j<110;j++)
maze[i][j]=maze1[i][j];
printf("\n程序将对此迷宫进行求解,入口(1,1) 出口(8,8)\n");
m=n=8;
entrancex=entrancey=1;
exitx=exity=8;
maze[entrancex][entrancey]=-1;
maze[exitx][exity]=-2;
outlin();
maze[entrancex][entrancey]=1;
maze[exitx][exity]=1;
printf("\n(如需自行创建迷宫使用<手动迷宫>项)\n");
printf("输入1求解此迷宫,输入0返回程序菜单:");
scanf("%d",&f);
system("cls");
while(1)
{
if(f==0)
return 0;
else if (f==1)
return 1;
else
{
printf("\n 输入错误,请重新输入1(求解迷宫)或0(返回程序菜单)\n") ;
scanf("%d",&f);
system("cls");
}
}
}
int outlin() //输出迷宫函数
{
int i,j;
if(finish==-1)
{
printf("\n\n没找到路!你的迷宫有问题...\n");
return 1;
}
else if(finish==2)
{
printf("\n\n 入口和出口重合了!\n");
return 1;
}
else if(finish==1)
printf("\n\n已成功查找出最短路径,输出如下:\n");
printf(" "); //开始输出图形。

for(j=0;j<n+2;j++)
printf("%2d",j);
printf("\n");
for(i=0;i<m+2;i++)
{
printf("%2d",i);
for(j=0;j<n+2;j++)
{
switch(maze[i][j])
{
case -1 :printf("入");break;
case -2 :printf("出");break;
case 0 :printf("■");break;
case 1 :printf(" ");break;
case 2 :printf("│");break;
case 3 :printf("─");break;
case 4 :printf("┌");break;
case 5 :printf("┐");break;
case 6 :printf("└");break;
case 7 :printf("┘");break;
}
}
printf("\n");
}
if(finish==1) //输出最优路径
{
q=L2->next;
printf("此路径的步进顺序为:\n");
while(q->next)
{
printf("(%d,%d)→",q->y,q->x);
q=q->next;
}
printf("(%d,%d)\n此路径已是最短路径,共%d步。

",exity,exitx,mindistance);
}
}
int formatmaze() //格式化迷宫。

再创建新迷宫时用。

{
int i,j;
for(i=0;i<m+2;i++)
for(j=0;j<n+2;j++)
maze[i][j]=0;
finish=0;
//以下语句把上次求解迷宫时建立的链表空间释放。

if(existL!=0)
{
while(L->next)
{
L=L->next;
free(L->pre);
}
free (L);
if(existL==2)
{
while(L2->next)
{
L2=L2->next;
free(L2->pre);
}
free (L2);
}
}
existL=0;
finish=0;
mindistance=0;
}
int chk(int direction) //判断下一个方向是否有障碍的函数。

{
nowstep->di++;
if(direction==1)
{
if(maze[(nowstep->x)-1][nowstep->y]==1)
return 1;
else
return 0;
}
else if(direction==2)
{
if(maze[nowstep->x][(nowstep->y)+1]==1)
return 1;
else
return 0;
}
else if(direction==3)
{
if(maze[(nowstep->x)+1][nowstep->y]==1)
return 1;
else
return 0;
}
else if(direction==4)
{
if(maze[nowstep->x][(nowstep->y)-1]==1)
return 1;
else
return 0;
}
}
int move(int direction)//如果chk函数判断下一点可通,则使用此函数实现走动
{
laststep=nowstep; //将laststep指向nowstep,再建立新的nowstep,实现nowstep的前进。

nowstep=(lnode *)malloc(sizeof(lnode));
nowstep->di=0;
nowstep->next=NULL;
nowstep->pre=laststep;
nowstep->stepsum=laststep->stepsum+1;
nowstep->x=laststep->x;
nowstep->y=laststep->y;
laststep->next=nowstep;
maze[laststep->x][laststep->y]=-1;//用-1将maze数组中的值标记,表示已经走过
switch(direction)
{
case 1: nowstep->x--;break;
case 2: nowstep->y++;break;
case 3: nowstep->x++;break;
case 4: nowstep->y--;
}
}
int back()
{
nowstep=laststep;
free(nowstep->next);
maze[nowstep->x][nowstep->y]=1;//将maze数组中标记的-1改为1,以便其他路径尝试时可以通过。

laststep=laststep->pre;
nowstep->next=NULL;
}
int revise() //│─┌┐└┘六个符号在maze数组里分别由2 3 4 5 6 7 表示.
{ int dx,dy;
p=L2->next->next;
while(p->next&&p->pre)
{
dx=(p->next->x)-(p->pre->x);
dy=(p->next->y)-(p->pre->y);
if(dy==0)
maze[p->x][p->y]=2;
else if(dx==0)
maze[p->x][p->y]=3;
else if(dx==1&&dy==1)
{
if(p->x==p->pre->x)
maze[p->x][p->y]=5;
else
maze[p->x][p->y]=6;
}
else if(dx==-1&&dy==1)
{
if(p->x==p->pre->x)
maze[p->x][p->y]=7;
else
maze[p->x][p->y]=4;
}
else if(dx==1&&dy==-1)
{
if(p->x==p->pre->x)
maze[p->x][p->y]=4;
else
maze[p->x][p->y]=7;
}
else if(dx==-1&&dy==-1)
{
if(p->x==p->pre->x)
maze[p->x][p->y]=6;
else
maze[p->x][p->y]=5;
}
p=p->next;
}
maze[exitx][exity]=-2;
maze[entrancex][entrancey]=-1;
}
int seek() //迷宫求解.
{
int allfinished=0;
if(entrancex==exitx&&entrancey==exity)//入口和出口重合的特殊情况。

return 2;
L=(linklist)malloc(sizeof(lnode));//建立存储脚步的链表.
L->next=NULL;
L->pre=NULL;
L->stepsum=0;
existL=1;
//初始化nowstep,令其在入口处。

nowstep=(lnode *)malloc(sizeof(lnode));
nowstep->x=entrancex;
nowstep->y=entrancey;
nowstep->pre=L;
nowstep->next=NULL;
nowstep->di=0;
nowstep->stepsum=1;
L->next=nowstep;
//开始查找第一条可通路径。

while(nowstep->x!=exitx||nowstep->y!=exity)//用1234代表↑→↓←四个方向。

{
if(nowstep->di==0&&chk(1)==1)
//可通必须满足两个条件,下一个点无障碍、下一个点未出现在已构建的路径中move(1);
else if(nowstep->di==1&&chk(2)==1)
move(2);
else if(nowstep->di==2&&chk(3)==1)
move(3);
else if(nowstep->di==3&&chk(4)==1)
move(4);
else if(nowstep->x==entrancex&&nowstep->y==entrancey)
//如果脚步停留在了入口,说明迷宫无解,不再查找。

return -1;
else
back();//本步无路了,回退。

}
mindistance=laststep->stepsum;
//OK,查找出了第一条路径L,说明迷宫有解。

建立L2比较路径,尝试寻找比L更短的路径。

if (laststep->stepsum==abs(entrancex-exitx)+abs(entrancey-exity)) //若第一条路径与理论最小路径相等,则不需要再次比较,直接返回。

{
L2=L;
revise();
return 1;
}
existL=2;
while(allfinished==0)
{
L2=(linklist)malloc(sizeof(lnode));
L2->next=NULL;
L2->pre=NULL;
L2->stepsum=0;
//将最后一个最小路径备份到L2,继续求解。

p=L2;
g=L->next;
while(g)
{
q=(lnode *)malloc(sizeof(lnode));
q->di=g->di;
q->stepsum=g->stepsum;
q->x=g->x;
q->y=g->y;
q->pre=p;
p->next=q;
g=g->next;
p=q;
}
q->next=NULL;
//开始查找第二条可通路径。

back();
while(nowstep->x!=exitx||nowstep->y!=exity)
{
if(nowstep->di==0&&chk(1)==1)
move(1);
else if(nowstep->di==1&&chk(2)==1)
move(2);
else if(nowstep->di==2&&chk(3)==1)
move(3);
else if(nowstep->di==3&&chk(4)==1)
move(4);
else
{
if(nowstep->stepsum==1&&nowstep->di==4)
//第一步的四个方向也都尝试过了,说明迷宫所有可能路径都已尝试完毕。

{
allfinished=1;
break;
}
back();
}
if (nowstep->stepsum>=mindistance)//新路径大于旧路径,就不要再往下尝试浪费时间了。

换其他路径。

back();
}
if(allfinished==0)//每次找到更短路径,都要存入L2,并销毁原L2释放空间。

{
mindistance=laststep->stepsum;
while(L2->next)
{
L2=L2->next;
free(L2->pre);
}
free (L2);
}
};
revise();
//改写maze数组里存储的内容,把每一步的方向信息写进去,以便输出图形路径。

return 1;
}
int creat()//创建迷宫
{
int i,j;
char cord='a';
system("cls");
do
{
if(cord=='r')
formatmaze();
printf("\n请输入迷宫行、列数(最大%d*%d)。

\n行:",maxsize,maxsize);
scanf("%d",&m);
printf("列:");
scanf("%d",&n);
while(m>maxsize||n>maxsize||m<1||n<1)
{
printf("输入有误。

只支持%d*%d以内的迷宫,请重新输入行列数。

\n行:",maxsize,maxsize);
scanf("%d",&m);
printf("列:");
scanf("%d",&n);
}
printf("\n输入迷宫数据,0为砖头,1为通路,数字间用空格间隔。

系统将自动添加围墙。

\n");
for(i=1;i<=m;i++)
{
printf("第%d行的%d个数据(共%d行):",i,n,m);
for(j=1;j<=n;j++)
scanf("%d",&maze[i][j]);
}
printf("\n已成功建立迷宫,图形如下:\n");
outlin();
printf("\n\n设定出入口数学坐标(x,y)。

\n已建立%d行%d列的迷宫,坐标应在(1,1)至(%d,%d)之间。

\n",m,n,n,m);
printf("设定入口坐标,格式示例1 1 : ");
scanf("%d %d",&entrancey,&entrancex);
while(entrancex>m||entrancey>n||maze[entrancex][entrancey]==0)
{
printf("输入有误,请检查。

坐标应在(1,1)至(%d,%d)之间。

\n请重新输入入口坐标,格式示例1,1 : ",n,m);
scanf("%d,%d",&entrancey,&entrancex);
}
printf("输入出口坐标,格式示例%d %d : ",n,m);
scanf("%d %d",&exity,&exitx);
while(exitx>m||exity>n||maze[exitx][exity]==0)
{
printf("输入有误,请检查。

坐标应在(1,1)至(%d,%d)之间。

\n请重新输入出口坐标,格式示例%d,%d : ",m,n,n,m);
scanf("%d,%d",&exity,&exitx);
}
system("cls");
printf("\n你设定的迷宫如下:\n");
maze[entrancex][entrancey]=-1;
maze[exitx][exity]=-2;
outlin();
maze[entrancex][entrancey]=1;
maze[exitx][exity]=1;
printf("入口和出口分别为(%d,%d)(%d,%d)。

\n键入y将开始求解,键入r 重新设定: ",entrancey,entrancex,exity,exitx);
scanf("%c%c",&cord,&cord);
while(cord!='y'&&cord!='r')
{
printf("输入有误,请重新输入: ");
scanf("%c%c",&cord,&cord);
}
system("cls");
}while(cord!='y');
}
int help() //帮助信息
{
system("cls");
printf("帮助信息\n");
}
int main()
{
int cord;
system("title 第五组:迷宫求解程序");
printf("\n********************************************************** **********************\n");
printf("\t\t\t\t迷宫求解程序\n\n\n");
printf("\t\t\t\t08信息与计算科学\n\n\n");
printf("\t * 超* 见\n\n");
printf("\t * 亮* 娜*敏\n\n");
printf("\t *琼*蒙*莉\n\n");
do{
printf("\n********************************************************** **********************");
printf("\t\t 程序菜单");
printf("\n┏━━━━━━━━━━━━━━━━━━━━━━━┓\n");
printf("┃\t1.自动演示");
printf("\t\t2.手动迷宫\t┃\n");
printf("┃\t3.程序帮助");
printf("\t\t4.退出程序\t┃\n");
printf("┗━━━━━━━━━━━━━━━━━━━━━━━┛\n");
printf("请选择1-4:");
scanf("%d",&cord);
switch(cord)
{
default :system("cls");printf("\n\n 您输入的不正确,请重新输入1~~~4之间的数。

\n\n");break;
case 1:if(autocreat()==0){formatmaze(); break;};finish=seek();outlin();formatmaze();break;
case 2:creat();finish=seek();outlin();formatmaze();break;
case 3:help();break;
case 4:exit(0);
}
}while(1);
}。

相关文档
最新文档