迷宫路径的求解(非递归方法和递归方法)

迷宫路径的求解(非递归方法和递归方法)

(对于非递归 求解一条通路即可,这里借助了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;
}


  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值