栈的应用--迷宫问题

问题描述:给定一个迷宫,给定入口和出口,找到从入口到出口的一条路径(任何一条路径都可以),迷宫为0表示可走,为1表示墙。用1将迷宫围起来避免边界问题。

实现思路:1.DFS搜索(递归)

2.采用的数据结构

下面分别用这两种方法来解决这个问题。

DFS搜索(即递归+回溯)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#define ROW 9
#define COL 9int integer[ROW][COL]={     //表示迷宫{1,0,1,1,1,1,1,1,1},{1,0,1,1,1,0,0,0,1},{1,0,0,0,0,0,1,0,1},{1,0,1,1,1,0,1,0,1},{1,0,1,0,0,0,1,0,1},{1,0,1,1,1,0,1,0,1},{1,0,0,0,0,1,1,0,1},{1,0,1,1,1,1,1,0,0},{1,1,1,1,1,1,1,1,1}
};
/*int integer[ROW][COL]={{2,0,2,2,2,2,2,2,2,2},//1{2,0,0,2,0,0,0,2,0,2},//2{2,0,0,2,0,0,0,2,0,2},//3{2,0,0,0,0,2,2,0,0,2},//4{2,0,2,2,2,0,0,0,0,2},//5{2,0,0,0,2,0,0,0,0,2},//6{2,0,2,0,0,0,2,0,0,2},//7{2,0,2,2,2,0,2,2,0,2},//8{2,2,0,0,0,0,0,0,0,0},//9{2,2,2,2,2,2,2,2,2,2} //10
}; 大家可以用这个迷宫进行再次观察*/int  print(int integer[ROW][COL],int x,int y);//打印该迷宫int dir[4][2]={
{1,0},{-1,0},
{0,1},{0,-1},
}  ;     //方向数组,代表 4 个方向int visted[120][120] ;    //  1  代表访问过  0 代表没有访问过int check(int x,int y) //检查下一步是否越界和是否已经走过以及是否是墙
{if(x< 0 || y<0 || x>= ROW || y>= COL)  return 0;if(visted[x][y])return 0;if(integer[x][y] !=  0 )return 0;return 1;
}int dfs(int x,int y)    //已经踏到了  x , y ,即x,y  可踏
{int xx,yy ,i ;usleep(100000);printf("\033c");print(integer,x,y);if(x ==  7 && y == 8 )exit(0);for(i= 0;i< 4 ;i++)   // 4 个方向 {xx =  x + dir[i][0];yy =  y + dir[i][1];if(check(xx,yy))    //xx ,yy 可踏上去{visted[xx][yy]= 1;dfs(xx,yy) ;visted[xx][yy] = 0 ;  //回溯}}usleep(100000); //再次打印,显示回溯的效果printf("\033c");print(integer,x,y);return 0;
}int print(int integer[ROW][COL],int x,int y)
{int i,j;for(i=0;i<ROW ;i++){for(j=0 ;j<COL ;j++){if(visted[i][j])printf("\033[41;32m  *  \033[0m") ;else printf("  %d  ",integer[i][j]);}printf("\n\n");}
}
int main(void)
{int i,j ;memset(visted,0,sizeof(visted));visted[0][1]=1;      //从入口出发dfs(0,1) ; 
}

运行截图:

这里写图片描述

PS 1.这是一个动态演示的程序,可以清晰的看到移动的动作,所以运行有奇效

2. 回溯之后要再打印一次,才能有回溯的效果,并且必须有sleep 函数,否则会因为程序运行太快而导致看不到回溯的效果。

3. 如果对于DFS搜索还不太懂的–>点这里,文中提到的马踏棋盘我会在下一篇博客中提到。

采用的数据结构

先来提出几个问题

1.为什么要用栈来实现?有什么好的地方?
2.di 有什么作用?为什么要它?
3.栈空与栈不空,有什么用?
4.大体思路是什么?
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#define  MAXSTACKSIZE  100  //栈的大小
#define      N          10     //二维迷宫大小
#define  Entrance_row   0  //入口
#define  Entrance_col   1 
#define  Exit_row   8   //出口
#define  Exit_col   9
typedef struct position{   //坐标   int x;int y;
}position ;
typedef struct SElement {position p;   int di;     //记录已经走了多少个方向
}SElement ; 
typedef struct Mystack{SElement  *top;SElement  *base;int stackSize ;
}Mystack ;int Maze[N][N]={{2,0,2,2,2,2,2,2,2,2},//1{2,0,0,2,0,0,0,2,0,2},//2{2,0,0,2,0,0,0,2,2,2},//3{2,0,0,0,0,2,2,0,0,2},//4{2,0,2,2,2,0,2,0,2,2},//5{2,0,0,0,2,0,0,0,0,2},//6{2,0,2,0,0,0,2,0,0,2},//7{2,0,2,2,2,0,2,2,0,2},//8{2,2,0,0,0,0,0,0,0,0},//9{2,2,2,2,2,2,2,2,2,2} //10
};int IsEmptyStack(Mystack *path);int InitStack(Mystack *path)   // top ,base  ,size 
{path->top = path->base =(SElement *)malloc(sizeof(SElement)*MAXSTACKSIZE);if(path->top == NULL ){printf("Init  stack is failed !!! \n");return -1;}path->stackSize = MAXSTACKSIZE;return 0;
}int pop(Mystack *path ,SElement *t)  //从path 中出一个元素给t 
{if(IsEmptyStack(path) == 1)return 0;*t = *(path->top-1);path->top-- ;return 1;
}int push(Mystack *path ,SElement p) //入栈
{*(path->top) = p ;path->top++;
}int IsEmptyStack(Mystack *path)
{if(path->top == path->base )   return 1;  //空栈返回 1  else return 0 ;
}
int print_MAZE(int Maze[N][N])  //打印迷宫
{int i,j;for(i= 0 ;i< N;i++){for(j= 0 ;j< N ;j++){if(Maze[i][j] == 10)    printf("\033[31m  *  \033[0m") ;else  printf("  %d  ",Maze[i][j]);}printf("\n\n");}
}
int check(position now_try) //检查下一步是否越界和是否是墙 
{if(Maze[now_try.x][now_try.y]  !=  0)  //0  代表走的通return 0;if(now_try.x <  0 && now_try.x >=  N  )return 0;if(now_try.y <  0 && now_try.y >=  N  )return 0;return 1;
}position   NextPosition(position  now_try ,int direction)  //获得下一个位置的坐标 x,y
{position next ;next.x= now_try.x;next.y  = now_try.y;switch(direction){case 4:next.y+=1;break; //东case 3:next.x+=1;break; //南case 1:next.x-=1;break;//西case 2:next.y-=1;break;//北}return next ;
}
int main(void)
{print_MAZE(Maze) ;Mystack  path ;InitStack(&path);position  now_try ; //所尝试的位置now_try.x= Entrance_row;now_try.y= Entrance_col;do{if(check(now_try)) //进入if 语句就说明这个点能走,就把他赋值为10 ,入栈,找下一步,继续{Maze[now_try.x][now_try.y]  =10 ;SElement temp ;temp.p.x= now_try.x;temp.p.y= now_try.y;push(&path,temp);if(now_try.x == Exit_row && now_try.y == Exit_col )break;now_try  = NextPosition(now_try,1);  //先向一个方向进行探索printf("\033c"); // 动态演示所走的路的语句print_MAZE(Maze);usleep(800000);}else     //这个点为 2 ,不能走,那么就取出它的上一个(即栈顶元素),寻找其他方向{if(IsEmptyStack(&path) !=  1)  //栈不空{SElement t ;pop(&path,&t);    //要在被调函数中改变twhile(t.di == 4 && IsEmptyStack(&path) !=  1){   //检查是否四个方向都已经被走过Maze[t.p.x][t.p.y] = 9 ;   //9 代表已经被探索过的路pop(&path,&t);}if(t.di < 4) //如果四个方向没有走够,就换一个方向走{now_try = NextPosition(t.p,t.di+1);t.di++;push(&path,t);}}}}while( IsEmptyStack(&path) ==  0  );  //0 就是有元素printf("\033c");print_MAZE(Maze);return 0;
}

运行截图:

这里写图片描述

问题解答:

1.首先我们都知道栈有先进后出的特点,那么我们的迷宫是否需要这种特点呐。如果走的通,那么就走,如果走不通,那是不是要回到前一步,找另外一个方向走。那么前一步怎么存储?是不是符合一个先存后取的顺序!OK !这不正好与我们的栈的特点重合吗。

2.di 的作用有两个。一是表示方向,二是表示走了几个方向了。是不是感觉很拗口。那么我来简单解释一下。用1,2,3,4来表示东南西北,如果di==3,那么就说明北面还没有走,如果di == 4,那么就说明四个方向都已经走过了。

3.栈空与栈不空,有什么用?假如我们将迷宫改成了这样,那么会发生什么?

int Maze[N][N]={{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2,2,2} 
};

是不是会依次入栈,然后依次出栈,出栈之后是不是会栈空,如果不判断栈空的话是不是会陷入一种死循环的状态呐。

4.核心代码:

    now_try.x= Entrance_row;now_try.y= Entrance_col;do{if(check(now_try)) //进入if 语句就说明这个点能走,就把他赋值为10 ,入栈,找下一步,继续{Maze[now_try.x][now_try.y]  =10 ;SElement temp ;temp.p.x= now_try.x;temp.p.y= now_try.y;push(&path,temp);if(now_try.x == Exit_row && now_try.y == Exit_col )break;now_try  = NextPosition(now_try,1);  //先向一个方向进行探索printf("\033c"); // 动态演示所走的路的语句print_MAZE(Maze);usleep(800000);}else     //这个点为 2 ,不能走,那么就取出它的上一个(即栈顶元素),寻找其他方向{if(IsEmptyStack(&path) !=  1)  //栈不空{SElement t ;pop(&path,&t);    //要在被调函数中改变twhile(t.di == 4 && IsEmptyStack(&path) !=  1){   //检查是否四个方向都已经被走过Maze[t.p.x][t.p.y] = 9 ;   //9 代表已经被探索过的路pop(&path,&t);}if(t.di < 4) //如果四个方向没有走够,就换一个方向走{now_try = NextPosition(t.p,t.di+1);t.di++;push(&path,t);}}}}while( IsEmptyStack(&path) ==  0  );  //0 就是有元素

大体思路:

这里写图片描述

参考资料:参考资料

转载于:https://www.cnblogs.com/Tattoo-Welkin/p/10335326.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/415551.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序 mpvue 生命周期一览

// vue 生命周期 beforeCreate () {console.log(vue [page-blog] beforeCreate) }, created () { console.log(vue [page-blog] created) }, beforeMount () { console.log(vue [page-blog] beforeMount) }, mounted () { console.log(vue [page-blog] mounted) }, beforeU…

工作129:动态路由

routes() {/*获取数据里面的控制业务端和营销端的mode数值*/const property Vue.ls.get(ACCESS_MODE);/*const *//* const showingMenu staticRoutes.filter(item){return !item.hidden}*//*去除里面的不是item.hidden是隐藏的属性*/const showingMenu staticRoutes.filte…

fragment dispatchTouchEvent

在父activity添加如下代码即可Override public boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() MotionEvent.ACTION_DOWN) {View v getCurrentFocus();if (isShouldHideKeyboard(v, ev)) {hideKeyboard(v.getWindowToken());}}return super.dispatchTouchE…

mpvue 微信小程序 显示 转发按钮

在js中定义 showShareMenu 函数&#xff0c;页面右上角就会出现转发的按钮。 官方文档 https://developers.weixin.qq.com/miniprogram/dev/api/share.html 具体想在哪个页面增加转发的按钮&#xff0c;就添加下面的代码 mounted() {wx.showShareMenu(); },这只是最简单的增加…

目录遍历漏洞

“目录遍历漏洞”指通过在URL或参数中构造“../”&#xff0c;或“../”和类似的跨父目录字符串的ASCII编码、unicode编码等&#xff0c;完成目录跳转&#xff0c;读取操作系统各个目录下的敏感文件&#xff0c;也可以称作“任意文件读取漏洞”。 ../ ..%2F /%c0%ae%c0%ae/ %2e…

!--[if IE 9] ![endif]--

<!--[if !IE]><!--> 除IE外都可识别 <!--<![endif]--><!--[if IE]> 所有的IE可识别 <![endif]--><!--[if IE 6]> 仅IE6可识别 <![endif]--><!--[if lt IE 6]> IE6以及IE6以下版本可识别 <![endif]--><!--[if gte …

Android 将图片网址url转化为bitmap,drawable转bitmap,file转bitmap,bitmap转file,Bitmap转String,Uri转Bitmap

file转bitmap File param new File(); Bitmap bitmap BitmapFactory.decodeFile(param.getPath(&#xff09;); drawable转bitmap Bitmap bmp BitmapFactory.decodeResource(getResources(),R.mipmap.jcss_03 ); url转bitmap Bitmap bitmap; public Bitmap returnBitMa…

小程序 web-view 打开 微信公众号文章

首先微信小程序不能不能随便打开一个网址就能进行访问。 必须要配置业务域名。 但是&#xff0c;如果小程序和微信公众号进行了关联&#xff0c;则直接可以打开这个公众号到文章。 我已经测试过了。肯定好用。 还有一种方案&#xff0c;打开别人公众号的文章&#xff0c;你…

IP协议包中的TTL(Time-To-Live)

TTL(Time-To-Live)的作用是限制数据包在网络中存在的时间&#xff0c;防止数据包不断的在IP互联网络上循环。 TTL指定数据包被路由器丢弃之前允许通过的最大网段数量&#xff0c;是IP数据包在网络中可以转发的最大跳数(跃点数)&#xff0c;TTL位于IPv4包的第9个字节&#xff0c…

常用的方法论-PARR

转载于:https://www.cnblogs.com/qjm201000/p/7687470.html

小程序 自定义遮照 mask 禁止上下滑动

要写一个提示框&#xff0c;有灰度&#xff0c;放到正常页面最外层。发现上下滑动&#xff0c;里层的页面也会跟着上下动&#xff0c;其实只需要再设置一下page的属性就行了。 <style lang"less" scoped>.verify-mask {z-index: 99999;position: fixed;top: 0…

修改wireshark协议解析规则

不同的协议有不同的解码器,wireshark尝试为每个包尝试找到正确的解码器,特定的情况有可能会选择错误的解码器。 1.使用了其它协议的标准端口&#xff0c;被错误解码&#xff0c;使用udp的80端口发送数据被当作QUIC协议解析。 wireshark菜单“Analyze–>Enabled Protocols…”…

java 泛型类使用,集合中添加不同类型数据

添加 ArrayList<String> a new ArrayList<String>(); a.add("CSDN_SEU_Cavin"); Class c a.getClass(); try{Method method c.getMethod("add",Object.class);method.invoke(a,100);System.out.println("lgqname:" a); }catch(Ex…

小程序 遮照 mask 背景透明,里面内容不透明

1、错误的写法 .mask {background: black;opacity: 0.5; }2、正确的写法 .mask {background: rgba(0, 0, 0, 0.5); }

skt框架开发设计1

本系列文章将从零开始设计一套后台服务器框架&#xff0c;框架基于插件开发模式&#xff0c;最终各个插件相互独立&#xff0c;互相不依赖&#xff0c; 这样设计的好处是最终开发人员负责各个模块的开发&#xff0c;相互之间能够相对独立的进行&#xff1b;转载于:https://www.…

java集合数组,数组小到大排序,数组大到小排序

List<?>[] lsa new List<?>[10]; // OK, array of unbounded wildcard type. Object o lsa; Object[] oa (Object[]) o; List<Integer> li new ArrayList<Integer>(); li.add(new Integer(3)); oa[1] li; // Correct. Integer i (Integer) lsa…