一般迷宫问题的求解
来源:互联网 发布:java如何实现方法重载 编辑:程序博客网 时间:2024/05/17 01:33
1.问题描述:
以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
2.基本要求
(1)首先实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。求得的通路以三元组(i,j,d)的形式输出。其中:(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。如,对于教材第50页图3.4所示的迷宫,输出一条通路为:(1,1,1),(1,2,2),(2,2,2),(3,2,3),(3,1,2),…。
(2)编写递归形式的算法,求得迷宫中所有可能的通路。
(3)以方阵形式输出迷宫及其通路。
这里除了书上要求的利用栈完成遍历,还有一个利用队列完成遍历并进行路径回收的算法
1.用链栈完成图的遍历并保存路径
基本思路:
由于DFS是盲目的,所以没有办法知道那个点可能到达最后的终点。所以需要引入一个father指针,指向某一点的前驱。在最后找到目标点时,再利用其父节点进行回溯
对于每一个可能的点入栈之后,专门一个指针指向它的父节点。
然后在进行pop的操作时,不将任何一个点free掉,否则father指针将会变成野指针,无法完成作用。
基本结构
typedef struct Node2{ int x,y,d; struct Node2 *next,*prior; struct Node2 *father;//father指针是回溯用的}Node2;typedef struct{ Node2 *head; Node2 *top;}LinkStack;
基本函数
初始化
LinkStack* Init(LinkStack *s){ s=(LinkStack*)malloc(sizeof(LinkStack*)); s->head=(Node2*)malloc(sizeof(Node2*)); s->top=s->head; s->head->x=s->head->y=0; s->head->next=s->head->prior=NULL; s->head->father=s->head; return s;}
Push操作
LinkStack* Push(LinkStack *s,Node2 *father,int x,int y){ Node2 *p=(Node2*)malloc(sizeof(Node2)); p->x=x; p->y=y; p->prior=s->top; p->father=father; p->next=NULL; p->d=0; s->top->next=p; s->top=s->top->next; return s;}
Pop操作
LinkStack* Pop(LinkStack *s){ Node2 *p=s->top; s->top=p->prior; //free(p);不能将p点free掉,否则无法完成回溯 return s;}
取栈顶元素
Node2* front(LinkStack *s,int &x,int &y){ Node2 *p=s->top; x=p->x; y=p->y; return s->top;}
指针回溯
Node2* Back(LinkStack* s){ return s->top->father;}
判断栈是否空
bool isempty(LinkStack *s){ if(s->top==s->head) return true; return false;}
DFS部分
void dfs1(int x,int y,int tarx,int tary){ int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; bool flag=false; LinkStack* s=Init(s); s=Push(s,s->head,x,y);//将起点压栈 visit[x][y]=false; int dx,dy; while(!isempty(s)) { Node2 *father=front(s,dx,dy); if(dx==tarx&&dy==tary){//达到终点,跳出循环 flag=true; break; } s=Pop(s); for(int i=0;i<4;++i){ dx+=dis[i][0]; dy+=dis[i][1]; if(check(dx,dy)){ s=Push(s,father,dx,dy);//可能到达的地方压栈 visit[dx][dy]=false; } } } if(!flag) cout<<"没有通路"<<endl; else{ int cnt=0; Road rpp[maxn]; while(1) { if(s->top->x==x&&s->top->y==y){ rpp[cnt].x=x; rpp[cnt].y=y; rpp[cnt].d=s->top->d; break; } Node2 *p=s->top->father; if(s->top->x>p->x)//根据上一个点判断是哪个方向 s->top->father->d=3; else if(s->top->x<p->x) s->top->father->d=1; else if(s->top->y>p->y) s->top->father->d=2; else s->top->father->d=4; rpp[cnt].x=s->top->x;//点的信息放入三元组 rpp[cnt].y=s->top->y; rpp[cnt].d=s->top->d; cnt++; s->top=Back(s); } for(int i=cnt;i>=0;--i) cout<<"("<<rpp[i].x<<","<<rpp[i].y<<","<<rpp[i].d<<")"<<endl; }}
递归完成图的遍历并输出所有通路
基本思想
要输出所有通路,其实就是把一个最简单的DFS添加一个DFS深度参数和一个路径保存数组。每次DFS都会更新数组,如果到达目标点,就可以把结果输出,然后去找下一个可能的路径。
基本结构
路径保存结构
typedef struct{ int x,y,d;}Road;
基本函数
方向判断
int dir(int x1,int y1,int x2,int y2){ if(x1<x2) return 1; else if(x1>x2) return 3; else if(y1<y2) return 2; else return 4;}
输出路径
void out(int len){ char mp1[110][110]; for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j) mp1[i][j]=mp[i][j]+'0'; } for(int i=0;i<=len;++i){ if(sol[i].d==1) mp1[sol[i].x][sol[i].y]='|'; else if(sol[i].d==2) mp1[sol[i].x][sol[i].y]='-'; else if(sol[i].d==3) mp1[sol[i].x][sol[i].y]='|'; else mp1[sol[i].x][sol[i].y]='-'; } for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j) cout<<mp1[i][j]; cout<<endl; } cout<<endl;}
DFS部分
void dfs2(int x,int y,int tarx,int tary,int k)//添加一个参数k代表深度{ sol[k].x=x;//记录路径 sol[k].y=y; sol[k-1].d=dir(sol[k-1].x,sol[k-1].y,sol[k].x,sol[k].y);//记录方向 if(x==tarx&&y==tary){ out(k); return ; } visit2[x][y]=false; int dx=x,dy=y; for(int i=0;i<4;++i){ dx+=dis[i][0]; dy+=dis[i][1]; if(check2(dx,dy)) dfs2(dx,dy,tarx,tary,k+1); } visit2[x][y]=true;}
利用队列完成遍历和路径回溯
基本思想
利用队列当然就是BFS,只不过出队并不能真正的删除数据,而且也需要一个father指针指向其父节点,最后跳回起点,完成路径回溯
基本结构
队列元素
typedef struct{ int x,y; int father;}Node;
队列
typedef struct{ Node data[maxn]; int l,r;}Queue;
路径记录
typedef struct{ int x,y,d;}Road;
BFS部分
void bfs(int x,int y,int tarx,int tary){ int pos; Queue que; Road rpp[maxn]; visit2[x][y]=false; Node a; bool flag=false; que.l=que.r=0; a.x=x;a.y=y;a.father=0; que.data[que.r++]=a; while(que.l!=que.r)//当队列不空 { Node b=que.data[que.l]; if(b.x==tarx&&b.y==tary){ pos=que.l; flag=true; break; } que.l++; for(int i=0;i<4;++i){//遍历四个方向 Node c; int dx=dis[i][0]; int dy=dis[i][1]; c.x=b.x; c.y=b.y; c.x+=dx; c.y+=dy; c.father=que.l-1; if(check2(c.x,c.y)){ que.data[que.r++]=c; visit2[c.x][c.y]=false; //及时进行标记 } } } if(!flag) cout<<"达不到出口"<<endl; else{ int cnt=0; while(1)//路径回溯 { rpp[cnt].x=que.data[pos].x; rpp[cnt].y=que.data[pos].y; if(rpp[cnt].x==x&&rpp[cnt].y==y){//到达出发点 cnt++; break; } int d=0,nextpos=que.data[pos].father; Node k=que.data[nextpos]; if(que.data[pos].x>k.x)//根据上一个点判断是哪个方向 d=3; else if(que.data[pos].x<k.x) d=1; else if(que.data[pos].y>k.y) d=2; else d=4; rpp[cnt].d=d; pos=que.data[pos].father;//回溯 cnt++; } for(int i=cnt-1;i>=0;--i) cout<<"("<<rpp[i].x<<","<<rpp[i].y<<","<<rpp[i].d<<")"<<endl; }}
全部代码
#include<bits/stdc++.h>using namespace std;const int maxn=1e4+10;typedef struct{ int x,y; int father;}Node;typedef struct{ Node data[maxn]; int l,r;}Queue;typedef struct{ int x,y,d;}Road;typedef struct Node2{ int x,y,d; struct Node2 *next,*prior; struct Node2 *father;}Node2;typedef struct{ Node2 *head; Node2 *top;}LinkStack;int mp[110][110];bool visit1[110][110];bool visit2[110][110];Road sol[maxn];int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};int m,n;LinkStack* Init(LinkStack *s){ s=(LinkStack*)malloc(sizeof(LinkStack*)); s->head=(Node2*)malloc(sizeof(Node2*)); s->top=s->head; s->head->x=s->head->y=0; s->head->next=s->head->prior=NULL; s->head->father=s->head; return s;}LinkStack* Push(LinkStack *s,Node2 *father,int x,int y){ Node2 *p=(Node2*)malloc(sizeof(Node2)); p->x=x; p->y=y; p->prior=s->top; p->father=father; p->next=NULL; p->d=0; s->top->next=p; s->top=s->top->next; return s;}LinkStack* Pop(LinkStack *s){ Node2 *p=s->top; s->top=p->prior; //free(p);不能将p点free掉,否则无法完成回溯 return s;}Node2* front(LinkStack *s,int &x,int &y){ Node2 *p=s->top; x=p->x; y=p->y; return s->top;}Node2* Back(LinkStack* s){ return s->top->father;}bool isempty(LinkStack *s){ if(s->top==s->head) return true; return false;}void print() //输出图{ for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j) cout<<mp[i][j]<<" "; cout<<endl; } cout<<endl;}bool check1(int x,int y) //防越界处理{ if(x>=1&&x<=n&&y>=1&&y<=m) if(visit1[x][y]) return true; return false;}bool check2(int x,int y) //防越界处理{ if(x>=1&&x<=n&&y>=1&&y<=m) if(visit2[x][y]) return true; return false;}void out(int len){ char mp1[110][110]; for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j) mp1[i][j]=mp[i][j]+'0'; } for(int i=0;i<=len;++i){ if(sol[i].d==1) mp1[sol[i].x][sol[i].y]='|'; else if(sol[i].d==2) mp1[sol[i].x][sol[i].y]='-'; else if(sol[i].d==3) mp1[sol[i].x][sol[i].y]='|'; else mp1[sol[i].x][sol[i].y]='-'; } for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j) cout<<mp1[i][j]; cout<<endl; } cout<<endl;}int dir(int x1,int y1,int x2,int y2){ if(x1<x2) return 1; else if(x1>x2) return 3; else if(y1<y2) return 2; else return 4;}void dfs2(int x,int y,int tarx,int tary,int k){ sol[k].x=x; sol[k].y=y; sol[k-1].d=dir(sol[k-1].x,sol[k-1].y,sol[k].x,sol[k].y); if(x==tarx&&y==tary){ out(k); return ; } visit2[x][y]=false; int dx=x,dy=y; for(int i=0;i<4;++i){ dx+=dis[i][0]; dy+=dis[i][1]; if(check2(dx,dy)) dfs2(dx,dy,tarx,tary,k+1); } visit2[x][y]=true;}void bfs(int x,int y,int tarx,int tary){ int pos; Queue que; Road rpp[maxn]; visit2[x][y]=false; Node a; bool flag=false; que.l=que.r=0; a.x=x;a.y=y;a.father=0; que.data[que.r++]=a; while(que.l!=que.r)//当队列不空 { Node b=que.data[que.l]; if(b.x==tarx&&b.y==tary){ pos=que.l; flag=true; break; } que.l++; for(int i=0;i<4;++i){//遍历四个方向 Node c; int dx=dis[i][0]; int dy=dis[i][1]; c.x=b.x; c.y=b.y; c.x+=dx; c.y+=dy; c.father=que.l-1; if(check2(c.x,c.y)){ que.data[que.r++]=c; visit2[c.x][c.y]=false; //及时进行标记 } } } if(!flag) cout<<"达不到出口"<<endl; else{ int cnt=0; while(1)//路径回溯 { rpp[cnt].x=que.data[pos].x; rpp[cnt].y=que.data[pos].y; if(rpp[cnt].x==x&&rpp[cnt].y==y){//到达出发点 cnt++; break; } int d=0,nextpos=que.data[pos].father; Node k=que.data[nextpos]; if(que.data[pos].x>k.x)//根据上一个点判断是哪个方向 d=3; else if(que.data[pos].x<k.x) d=1; else if(que.data[pos].y>k.y) d=2; else d=4; rpp[cnt].d=d; pos=que.data[pos].father;//回溯 cnt++; } for(int i=cnt-1;i>=0;--i) cout<<"("<<rpp[i].x<<","<<rpp[i].y<<","<<rpp[i].d<<")"<<endl; }}void dfs1(int x,int y,int tarx,int tary){ bool flag=false; LinkStack* s=Init(s); s=Push(s,s->head,x,y);//将起点压栈 visit1[x][y]=false; int dx,dy; while(!isempty(s)) { Node2 *father=front(s,dx,dy); if(dx==tarx&&dy==tary){//达到终点,跳出循环 flag=true; break; } s=Pop(s); for(int i=0;i<4;++i){ dx+=dis[i][0]; dy+=dis[i][1]; if(check1(dx,dy)){ s=Push(s,father,dx,dy);//可能到达的地方压栈 visit1[dx][dy]=false; } } } if(!flag) cout<<"没有通路"<<endl; else{ int cnt=0; Road rpp[maxn]; while(1) { if(s->top->x==x&&s->top->y==y){ rpp[cnt].x=x; rpp[cnt].y=y; rpp[cnt].d=s->top->d; break; } Node2 *p=s->top->father; if(s->top->x>p->x)//根据上一个点判断是哪个方向 s->top->father->d=3; else if(s->top->x<p->x) s->top->father->d=1; else if(s->top->y>p->y) s->top->father->d=2; else s->top->father->d=4; rpp[cnt].x=s->top->x;//点的信息放入三元组 rpp[cnt].y=s->top->y; rpp[cnt].d=s->top->d; cnt++; s->top=Back(s); } for(int i=cnt;i>=0;--i) cout<<"("<<rpp[i].x<<","<<rpp[i].y<<","<<rpp[i].d<<")"<<endl; }}int main(){ freopen("in.txt","r",stdin); int x,y,tarx,tary; memset(visit1,true,sizeof(visit1)); memset(visit2,true,sizeof(visit2)); memset(mp,1,sizeof(mp)); cout<<"输入n和m,起点坐标和目标点坐标"<<endl; cin>>n>>m>>x>>y>>tarx>>tary; cout<<"输入图"<<endl; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ cin>>mp[i][j]; if(mp[i][j]){ visit2[i][j]=false; visit1[i][j]=false; } } dfs1(x,y,tarx,tary); cout<<endl; dfs2(x,y,tarx,tary,0); return 0;}
阅读全文
0 0
- 一般迷宫问题的求解
- 迷宫问题的求解
- 迷宫问题的递归求解
- 简单迷宫问题的求解
- 求解木乃伊迷宫问题的源代码
- 基于栈操作的迷宫问题求解
- 利用堆栈实现迷宫问题的求解
- 迷宫问题的C语言求解
- 栈的思想用于求解迷宫问题
- 迷宫求解问题
- 递归求解迷宫问题
- 迷宫问题求解
- 迷宫问题递归求解
- 迷宫问题求解
- 迷宫求解问题
- BFS求解迷宫问题
- 栈求解迷宫问题
- 栈求解迷宫问题
- 将字符串数字转化为数字相加再返回结果
- java基础【07】swing事件注册
- 在线体验ubuntu的方法
- UML设计九种图例
- 2017考研经验贴
- 一般迷宫问题的求解
- java面试总结
- Cmake简单实例
- 我怀念的
- 自定义View圆环进度条
- map表的一些用法
- C++11中std::mutex的使用
- Spring用bean.xml注入对象
- HTML5 4 视频