迷宫路径的求解(非递归方法和递归方法)
(对于非递归 求解一条通路即可,这里借助了pre[ ][ ]数组记录前驱)
(非递归的辅助栈为链栈)
代码示例
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000;
const int dx[5]={0,0,1,0,-1};
const int dy[5]={0,1,0,-1,0};
struct Point{
int x,y;
};
typedef struct Snode{
Point data;
struct Snode *next;
}Snode,*Linkstack;//链栈
void initstack(Linkstack &S)
{
/*链栈初始化,有头结点*/
S=(Linkstack)malloc(sizeof(Snode));
S->next=NULL;
}
bool emptystack(Linkstack S)
{
/*判断链栈是否为空*/
if(S->next==NULL) return true;
else return false;
}
void push(Linkstack &S,Point e)
{
//将一个数据e放入链栈
//头结点端为栈顶端
Linkstack p=(Linkstack)malloc(sizeof(Snode));
p->data=e;
p->next=S->next;
S->next=p;
}
void pop(Linkstack &S,Point &e)
{
/*将栈顶弹出,保存在e中返回*/
if(S->next==NULL) return ;//栈为空
Linkstack p=S->next;
e=p->data;
S->next=p->next;
free(p);//释放空间
}
int maze[maxn][maxn];//表示迷宫信息的二维数组
char maze1[maxn][maxn];//辅助迷宫,最后由数组转字符用
bool visit[maxn][maxn];//dfs过程中判断某个位置是否已经访问过
Point pre[maxn][maxn];//记录每个位置的前驱,用于非递归
Point solution[maxn*maxn];//记录方案路径上的点
int m,n;//迷宫m行n列
bool flag=0;//标记
void Input_maze()
{
/*用二维数组读入迷宫信息*/
for(int i=1;i<=m;++i)
for(int j=1;j<=n;++j)
scanf("%d",&maze[i][j]);
}
void Output_maze()
{
/*输出迷宫信息*/
printf("迷宫为:\n");
for(int i=1;i<=m;++i){
for(int j=1;j<=n;++j) printf("%d ",maze[i][j]);
printf("\n");
}
printf("\n");
}
int getdirection(Point a,Point b)//a为起点,b为终点
{
/*返回点x->点y的方向(保证x与y是相邻节点)*/
for(int i=1;i<=4;++i)
if(a.x+dx[i]==b.x&&a.y+dy[i]==b.y) return i;
}
void output1()
{
/*以三元组形式输出任务一中的一条通路*/
int len=0;
Point p={m,n};//既然调用output1,则说明已能到m,n点,则从该点开始
while(!(p.x==1&&p.y==1))//这里相当于solution里存放从终点到起点
{//所经历的点的坐标,即先放进数组的是离终点进的点
solution[++len]={p.x,p.y};//利用pre给solution赋值
p=pre[p.x][p.y];
}
solution[++len]={1,1};//最后放起点
for(int i=len;i>=2;--i)//从起点(len位置)开始,根据solution相邻点打印方向
{
printf("(%d,%d,%d)->",solution[i].x,solution[i].y,getdirection(solution[i],solution[i-1]));
}
printf("(%d,%d,0)\n\n",m,n);
}
bool check(Point u)
{
/*判断在搜索过程中一个点u是否可以到达(包括是否是障碍节点以及是否已经遍历过)*/
return maze[u.x][u.y]==0&&!visit[u.x][u.y]&&u.x>=1&&u.y>=1&&u.x<=m&&u.y<=n;
}
void solve1()//非递归模拟dfs
{
/*求出(1,1)->(n,m)的一条通路*/
printf("任务1:\n\n");
Linkstack S;//指向头结点的指针
initstack(S);
push(S,{1,1});
memset(visit,0,sizeof(visit));
visit[1][1]=1;
while(!emptystack(S))//非空
{
Point u;
pop(S,u);//取出栈顶
if(u.x==m&&u.y==n){//判断是否已经到达终点,如果到达就输出该组解
output1();
return;
}
for(int i=1;i<=4;++i)//四方向扩展
{
Point v;
v.x=u.x+dx[i];
v.y=u.y+dy[i];
if(!check(v)) continue;//这个方向不满足条件
visit[v.x][v.y]=1;
pre[v.x][v.y]=u;//该点的前驱结点为u
//主要是因为非递归的DFS不能直接带着第几步的参数
//所以借用pre二维数组,不断更新每一个点的前驱点
//也可以在Point结构体中加上计数器(类似BFS)
push(S,v);//新的节点入栈
}
}
printf("没有通路!\n\n");//while过程结束都没有返回则说明无解
}
void output2(int len)
{
/*以点阵形式输出所有通路*/
for(int i=1;i<=m;++i)
for(int j=1;j<=n;++j)
maze1[i][j]=maze[i][j]+48;
for(int i=1;i<len;++i){//对路径上的len个点中前len-1个换成指向下一个点的方向
int x=solution[i].x;
int y=solution[i].y;
int d=getdirection(solution[i],solution[i+1]);
if(d==1) maze1[x][y]='>';//向右
if(d==2) maze1[x][y]='|';
if(d==3) maze1[x][y]='<';//向左
if(d==4) maze1[x][y]='|';
}
flag=1;//做个有解的标记
for(int i=1;i<=m;++i){//变换后直接输出
for(int j=1;j<=n;++j)
printf("%c ",maze1[i][j]);
printf("\n");
}
printf("\n");
}
void dfs(int k,int x,int y)
{
/*k表示当前走到第几步,x,y表示当前的位置*/
solution[k]={x,y};
visit[x][y]=1;
if(x==m&&y==n) output2(k);//如果到了终点就输出此方案
else
for(int i=1;i<=4;++i)//四个方向遍历
{
int u=x+dx[i],v=y+dy[i];
if(!check({u,v})) continue;
dfs(k+1,u,v);
}
visit[x][y]=0;//回溯,visit信息清零
}
void solve2()
{
/*求出(1,1)->(n,m)的所有通路*/
printf("任务2:\n\n");
flag=0;
memset(visit,0,sizeof(visit));
dfs(1,1,1);
if(!flag) printf("没有通路!\n\n");
}
int main()
{
//freopen("C://Users//Francis//Desktop//mycode//read.txt","r",stdin);
int cas=0;
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(maze,0,sizeof(maze));
memset(visit,0,sizeof(visit));
cas++;
printf("Test %d:\n",cas);
Input_maze();
Output_maze();
solve1();
solve2();
printf("***********************************************************\n");
}
return 0;
}