1.问题描述:
以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
2.基本要求:
(1)首先实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。求得的通路以三元组(i,j,d)的形式输出。其中:(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。
(2)编写递归形式的算法,求得迷宫中所有可能的通路。以方阵形式输出迷宫及其通路。
3.原理:
①. 链栈:用链式结构实现的栈,即只能从栈顶进出的链表,需要用到的函数有:栈的初始化:voidInit_S(Linkstack &S);判断链栈是否为空: intIsEmpty(Linkstack S);压栈:void Push(Linkstack&S,SElemType e);出栈:void Push(Linkstack&S,SElemType e)
②. DFS遍历思想:定义一地图数组map[N],一标记数组vis[N],一方向数组dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};表示下,上,右,左四个方向(因为二维数组是个矩阵)。从起点往终点方向走,遇到障碍停下(map[x]为障碍标记1时),走过处进行标记(vis[x]改为1)。一直走到终点。
4.思路:
①a.对于非递归,首先初始化一个栈,将起点的坐标放入栈中,并使此处标记数组的值变为1(开始都初始化为0)。进入循环,当栈不空时,取栈顶,若不为终点坐标,则在周围四个方向进行搜索,满足条件(1不为障碍,2未走过)即放入栈中,将此坐标标记数组改为1,并用pre数组记录前驱,若为终点坐标,则输出这一组解,函数终止。b.由于要以三元组形式输出,计算方向即成了关键。可用先前存储的pre前驱数组来进行计算。由于从栈顶依次输出,顺序与走迷宫顺序相反,故应从高下标端向低下标断打印。
②a.对于递归打印所有情况,调用DFS函数,若到达终点,则调用OutPut2函数,输出此方案,否则,对四个方向遍历,递归调用DFS,(每次调用完成后vis回溯至0),直至输出所有情况.b.由于要用矩阵形式输出迷宫走法(通路),故在计算方向的时候用D,U,R,L分别替代通路上的坐标(分别表示DOWN,UP,RIGHT,LEFT)。因此需先将mp数组变为字符数组mp2。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define maxn 1000
using namespace std;
int n,m;//n*m迷宫
int flag=0; //若有能到终点的路,则flag变为1
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //方向数组 ,分别为下,上,右,左 ,输出分别设为0,1,2,3
int vis[maxn][maxn];//DFS标记数组
int mp[maxn][maxn]; //输入的迷宫
char mp2[maxn][maxn]; //待输出的迷宫
typedef struct Point
{
int x,y;
}SElemType;
SElemType pre[maxn][maxn];//记录每个位置的前驱
SElemType solution[maxn*maxn];//方案记录数组
//链栈定义及操作
typedef struct Snode
{
SElemType data;
struct Snode *next;
}Snode,*Linkstack;
void Init_S(Linkstack &S)//初始化
{
S=(Linkstack)malloc(sizeof(Snode));
S->next=NULL;
}
int IsEmpty(Linkstack S) //判断链栈是否为空
{
if(S->next==NULL) return 1; //1表示为空
else return 0;
}
void Push(Linkstack &S,SElemType e) //压栈
{
Linkstack p=(Linkstack)malloc(sizeof(Snode));
p->data=e;
p->next=S->next;
S->next=p;
}
void Pop(Linkstack &S,SElemType &e) //出栈
{
if(S->next==NULL) return ;
Linkstack p=S->next;
e=p->data;
S->next=p->next;
free(p);
}
int Check(SElemType u) //检查点是否有障碍和是否已经遍历过
{
if(mp[u.x][u.y]==0&&vis[u.x][u.y]==0)
return 1;
else return 0;
}
void Input() //输入迷宫
{
memset(mp,1,sizeof(mp));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
cin>>mp[i][j];
}
void Output() //输出迷宫
{
printf("迷宫为:\n\n");
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
cout<<mp[i][j];
cout<<endl;
}
cout<<endl;
}
int Direction(SElemType a,SElemType b) //节点a->b的方向(方向数组做了解释)
{
for(int i=0;i<4;++i)
if(b.x==a.x+dir[i][0]&&b.y==a.y+dir[i][1])
return i;
}
void Output1(int inx,int iny,int outx,int outy) //以三元组形式输出一条通路
{
int len=0;
SElemType p={outx,outy};
while(!(p.x==inx&&p.y==iny))
{
solution[++len]={p.x,p.y};
p=pre[p.x][p.y];
}
solution[++len]={inx,iny};
for(int i=len;i>=2;--i)
{
printf("(%d,%d,%d)\n",solution[i].x,solution[i].y,Direction(solution[i],solution[i-1]));
}
printf("(%d,%d,OK)\n\n",n,m);//到达终点
}
void Solve1(int a,int b,int c,int d)
{
cout<<"项目1:非递归输出:"<<endl;
memset(vis,0,sizeof(vis));
Linkstack S;
Init_S(S);
Push(S,{a,b});
vis[a][b]=1;
while(!IsEmpty(S))
{
SElemType u,v;
Pop(S,u); //取栈顶
if(u.x==c&&u.y==d){
Output1(a,b,c,d); //到达终点输出一组解
return ; //并终止函数 (按题意)
}
for(int i=0;i<4;i++){
v.x=u.x+dir[i][0];
v.y=u.y+dir[i][1];
if(!Check(v)) continue;
vis[v.x][v.y]=1;
pre[v.x][v.y]=u;
Push(S,v);
}
}
cout<<"无通路,请重新输入"<<endl;
}
void Output2(int len)
{
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
mp2[i][j]=mp[i][j]+48;
for(int i=1;i<len;++i)
{
int x=solution[i].x,y=solution[i].y,d=Direction(solution[i],solution[i+1]);
if(d==0) mp2[x][y]='D';
if(d==1) mp2[x][y]='U';
if(d==2) mp2[x][y]='R';
if(d==3) mp2[x][y]='L'; //DOWN,UP,RIGHT,LEFT
}
flag=1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
printf("%c ",mp2[i][j]);
printf("\n");
}
printf("\n");
}
void DFS(int k,int inx,int iny,int outx,int outy)
{
/*k表示当前走到第几步,x,y表示当前的位置*/
solution[k]={inx,iny};
vis[inx][iny]=1;
if(inx==outx&&iny==outy) Output2(k);//如果到了终点就输出此方案
else
for(int i=0;i<4;++i)//四个方向遍历
{
int u=inx+dir[i][0],v=iny+dir[i][1];
if(!Check({u,v})) continue;
DFS(k+1,u,v,outx,outy);
}
vis[inx][iny]=0;//回溯,vis信息清零
}
void Solve2(int a,int b,int c,int d)
{
cout<<"项目1:递归输出:"<<endl;
flag=0;
memset(vis,0,sizeof(vis));
DFS(1,a,b,c,d);
if(!flag) cout<<"无通路,请重新输入"<<endl;
}
int main(){
freopen("text1.txt","r",stdin);
while(cin>>n>>m)
{
int a,b,c,d;
cout<<"输入起点、终点:"<<endl; //(a,b)起点,(b,c)终点
cin>>a>>b>>c>>d;
Input();
Output();
Solve1(a,b,c,d);
Solve2(a,b,c,d);
cout<<"xxxxxxxxxxxxxxxxxxxxxx"<<endl;
}
return 0;
}