zoukankan      html  css  js  c++  java
  • BFS-迷宫问题-用宽度(广度)优先搜索解决最优路径问题

    题目:
    给定一个大小为 N×M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格
    的通道移动。请求出从起点到终点所需的最小步数。请注意,本题假定从起点一定可以移动
    到终点。
    限制条件;N, M ≤ 100

    测试样例:
    N=10, M=10(迷宫如下图所示。 '#', '.', 'S', 'G'分别表示墙壁、通道、起点和终点)

    #S######.#
    ......#..#
    .#.##.##.#
    .#........
    ##.##.####
    ....#....#
    .#######.#
    ....#.....
    .####.###.
    ....#...G#
    

    输出结果:
    22

    关于深度优先搜索我在之前的博客中有提及:深度优先搜索初尝试
    以及小z的房子

    那么这道题目能不能用深度优先搜索解决呢?
    很遗憾,深度优先搜索做不到。

    在经过三次尝试以后,得出了DFS解此题的几大缺陷

    • 1.深度优先搜索,顾名思义,对一条可能的路径搜索至无法在搜索,再对下一条路径进行搜索。那么当利用栈来进行DFS搜索,记录最短路径的步数,怎么实现?就算你把已经搜索过的位置标记,再利用标记来减去多余的步数,实现的语句也是非常亘长和麻烦的。
    • 2.那么我用队列来存储可以吗?在第一点,大部分实现DFS算法都是利用栈,那么也带来了一定的麻烦,你经过的每一点都被压入栈中,并且因为栈的后进先出(LIFO),导致每一次搜索分支结束以后,返回的时候(如果没有找到终点),都需要退栈。如果使用队列的话就不会这么麻烦。
      那么用队列实现的“特别的”DFS算法,能不能行的通?答案也是否定的,原因也是因为记录最短路径的步数问题,每次压入队列都有多个坐标。读者可以自己画一个队列进行模拟。
    • 3.DFS搜索到的路径未必是最短的。如果有两条路径可以抵达终点,那么DFS最初所选择的路径未必是最短的。

    用BFS(queue)来实现:
    代码:

    #include<cstdio>
    #include<stdlib.h>
    #include<iostream>
    #include<string>
    #include<queue>
    #define INF 1000;//定义INF; 
    using namespace std;
    struct p
    {
    	int x,y;
    };//存储坐标 
    
    int k;
    int n,m;
    
    int change[6][3]={{1,0},{-1,0},{0,1},{0,-1}};
    char pla[105][105];
    int dpla[105][105];//存储每一点距离的数组 
    
    void BFS(int beginx,int beginy)
    {
    	int i,j;
    	queue<p>q;//存储坐标的队列 
    	
    	p begin,between;
    	begin.x=beginx;
    	begin.y=beginy;
    	
    	q.push(begin);
    	 
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)
    		{
    			dpla[i][j]=INF;//所有位置的距离初始化为INF; 
    		} 
    	}
    	
    	dpla[begin.x][begin.y]=0;//开始的地方设置为0;
    	pla[begin.x][begin.y]='z';//用'z'替换掉原来的‘.’防止走回去 
    	
    	while(!q.empty())
    	{	
    		begin=q.front();//取出队首开始搜索 
    		q.pop();
    		if(pla[begin.x][begin.y]=='g')break;//遇到终点break; 
    		
    		for(i=0;i<4;i++)
    		{
    			between.x=begin.x+change[i][0];
    			between.y=begin.y+change[i][1];//上下左右搜索 
    			
    			if(between.x>0 && between.x<=n && between.y>0 && between.y<=m)
    			{
    				if(pla[between.x][between.y]=='.')
    				{
    					q.push(between);//入列 
    					//在dpla记录每一个坐标的距离 
    					dpla[between.x][between.y]=dpla[begin.x][begin.y]+1;
    					
    					pla[between.x][between.y]='z';//字符替换,声明已经走过 
    				}
    				if(pla[between.x][between.y]=='G')//遇到终点 
    				{
    					q.push(between);//终点入列;
    					//记录至终点的距离 
    					dpla[between.x][between.y]=dpla[begin.x][begin.y]+1;
    					
    					pla[between.x][between.y]='g';//用g替换G,代表搜索到终点; 
    				}
    			}
    		}
    		
    	} 
    	
    }
    
    int main()
    {
    	int i,j;
    	scanf("%d%d",&n,&m);
    	
    	getchar();//回车 
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)
    		{
    			scanf("%c",&pla[i][j]);
    		}
    		getchar();
        }
        
        for(i=1;i<=n;i++)
        {
        	for(j=1;j<=m;j++)
        	{
        		if(pla[i][j]=='S')//找到出发点; 
        		BFS(i,j);
        	}
        }
        
        //下面注释的代码判断距离有没有出错 
        /*for(i=1;i<=n;i++)
        {
        	for(j=1;j<=m;j++)
        	{
        		printf("%d ",dpla[i][j]);
        	}
        	printf("
    ");
        }*/ 
        
        for(i=1;i<=n;i++)
        {
        	for(j=1;j<=m;j++)
        	{
        		if(pla[i][j]=='g')
        		printf("%d",dpla[i][j]);//输出终点记录的距离; 
        	}
        }
        
        return 0;
    }
    

    主要注意的地方和变量的名称我在代码中作了注释。写起来其实和DFS差不多,一个明显不同的地方就是用了一个数组dpla存储每一个坐标与原点坐标的距离。
    我在敲这段程序的时候,犯了一个错误:忘记对搜索过的区域.进行字符的替换,这样会导致循环无法结束。

    昭锡对BFS也有作一篇文章:迷宫问题
    关于DFS和BFS深入的理解及其他:BFS和DFS算法介绍与实现 作者:yousheng324。

    2016/3/16

  • 相关阅读:
    CentOS6.7 mysql5.6.33修改数据文件位置
    win8 win10 安装msi 提示2502、2503的错误代码
    2016年国内开源镜像站点汇总
    eclipse创建本地maven
    maven添加sqlserver的jdbc驱动包
    CentOS6.5下RPM方式安装mysql5.6.33
    linux中~和/的区别
    Linux命令学习(22):ss命令
    Linux命令学习(21):netstat命令
    Linux命令学习(20):traceroute命令
  • 原文地址:https://www.cnblogs.com/qq952693358/p/5281794.html
Copyright © 2011-2022 走看看