zoukankan      html  css  js  c++  java
  • BFS 典型的迷宫问题

    这个是BFS搜索的典型问题,好好整理一下:

        给定一个迷宫,入口为左上角,出口为右下角,问是否有路径从入口到出口,若有则输出一条这样的路径。注意移动可以从上、下、左、右、上左、上右、下左、下右八个方向进行。迷宫输入0表示可走,输入1表示墙。易得可以用1将迷宫围起来避免边界问题。本题采用BFS算法给出解。注意,利用BFS算法给出的路径必然是一条最短路径。

    input:

    1

    6 8

    0 1 1 1 0 1 1 1

    1 0 1 0 1 0 1 0

    0 1 0 0 1 1 1 1

    0 1 1 1 0 0 1 1

    1 0 0 1 1 0 0 0

    0 1 1 0 0 1 1 0

    output:

    YES

    (1,1) (2,2) (3,3) (3,4) (4,5) (4,6) (5,7) (6,8)

        基本思路:

        采用BFS的思路,每个位置相当于一个结点,用BFS进行广度搜索,相当于往外一环一环扩散的感觉,最后看能否达到出口的位置。

        实现以及技巧:

        1.基本的数据结构:相比对于一棵树的BFS来说,这里的BFS中的Node是一个坐标,因此要自定义好结点,typedef struct Node{int x; int y;}Node;BFS里面要用到队列,对基本的队列的库函数的声明和使用要熟悉,Q.size() Q.push(Node) Q.front() 以及Q.pop()

        2.关于path的问题:由于要存储路径信息,这里的path是一个二维的指针数组,注意这种声明以及初始化的方式:声明Node **path;初始化:

         path=new Node*[MAXL];

         for(i=0;i<=MAXL;i++)

         {path[i]=new Node[MAXH];}

        应该还有其他的表述方式,总之要会用一个,这里涉及到二维时候的指针还是挺麻烦的。

        3.还要注意每次path的更新点的选择问题,在每次元素入队的时候,比如当前元素为now,检查它周围的8个点,让没有墙的点入队,比如一个没有墙的点是temp就在这个位置上更新,path[temp.x][temp.y]=now。

        4.path输出的问题也很重要,这个最好就记下来,就是递归输出,比较典型,具体看代码的outputpath函数。

        5.考虑向周围移动的时候:向周围的8个点移动的时候可以先设置好一个二维数组:

        Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}};

        之后一个循环,把对应的x y值加上去就好,这样比较省事。注意结构体赋初值的时候也可以用这种小括号的形式:Node start={1,1};

        6.还有一点容易忽略,想周围移动的时候,已经探测过的点要做个标记,比如标记成-1或者类似的,这样就不会绕回去了,否则有可能形成一个环。

        7.还有其他的技巧,就是在地图初始化的时候,在周围加上一圈的围墙,这样在具体BFS的时候就不用再考虑边界的问题了。

    具体代码如下:

    //http://blog.csdn.net/that163/article/details/8069764
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define MAXH 20
    #define MAXL 20
    using namespace std;
    
    typedef struct Node{
        int x;
        int y;
    }Node;
    
    //记录地图信息
    int maze[MAXH][MAXL];
    //记录路径信息
    //Node*path[MAXH][MAXL];
    Node **path;
    Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}};
    
    bool BFS(Node start,Node end)
    {
        int i;
        Node tempN;
        Node tempNM;
        queue<Node>Q;
        Q.push(start);
        maze[start.x][start.y]=-1;
        
        //while(tempN.x!=end.x&&tempN.y!=end.y&&Q.size!=0)
        while(Q.size()!=0)
        {
            tempN=Q.front();
            Q.pop();
            //遍历8个方向全部的点
            for(i=0;i<8;i++)
            {
                tempNM.x=tempN.x+move[i].x;
                tempNM.y=tempN.y+move[i].y;
                //若是移动之后的点 位置是0 表示可以通过
                if(tempNM.x>=1&&tempNM.y>=1&&tempNM.x<=end.x&&tempNM.y<=end.y&&maze[tempNM.x][tempNM.y]==0)
                {
                    //孩子结点入队
                    Q.push(tempNM);
                    //已经尝试过的点标记成-1
                    maze[tempNM.x][tempNM.y]=-1;
                    path[tempNM.x][tempNM.y]=tempN;
                }
            }
            
        }
    
        if(tempN.x==end.x&&tempN.y==end.y)
        {return true;}
        else
        {return false;}
        
        
    }
    
    void outputpath(Node end)
    {
        //可以递归输出
        Node temp=end;
        if(end.x==1&&end.y==1)
        {
            printf("(%d,%d)",end.x,end.y);
            return;
        }
        else
        {
            //取出指针的内容
            temp=path[temp.x][temp.y];
            outputpath(temp);
            if(temp.x!=1&&temp.y!=1)
            {printf("(%d,%d)",temp.x,temp.y);}
        }
        
        return;
        
    }
    
    
    int main()
    {
        freopen("in.txt","r",stdin);
        int hang,lie,N;
        int i,j;
        scanf("%d",&N);
        while(N--)
        {
            //输入部分
            scanf("%d%d",&hang,&lie);
            for(i=1;i<=hang;i++)
            {
                for(j=1;j<=lie;j++)
                {
                    if(j==lie)
                    {
                        scanf(" %d",&maze[i][j]);
                    }
                    else
                    {
                        scanf("%d",&maze[i][j]);
                    }
                }
            }
            
            
            Node start={1,1};
            //注意结构体的这种用中括号来赋值的方式
            Node end={hang,lie};
            
            //二维指针数组的规定初始值的方式
            //此时path是一个指向一维指针数组的指针
            path=new Node*[MAXL];
            for(i=0;i<=MAXL;i++)
            {path[i]=new Node[MAXH];}
            
            
            //调用BFS函数进行搜索 更新path矩阵信息 
            bool connect=BFS(start,end);
            if(connect)
                puts("YES");
            else
                puts("NO");
                
            
            //输出路径信息
            outputpath(end);
            
            printf("(%d,%d)
    ",6,8);
            
        }
        
        
        return 0;
    }
  • 相关阅读:
    今天早上打算去菜市场看看是否开张
    昨天晚上雨岳阳通话后,晚上睡着肚子咕咕叫
    已经一周没有开锅了
    今天早上6:00起来,每天晚上回来6点多已经天黑
    其实值班也是一个说法
    感觉每天虽然没有做什么,但是就是觉得睡不够
    现在进入秋季,上海也是在20度左右
    mysql 下 计算 两点 经纬度 之间的距离 含具体sql语句
    java解析xml的几种方式
    myeclipse安装svn插件的多种方式
  • 原文地址:https://www.cnblogs.com/Goden/p/3962131.html
Copyright © 2011-2022 走看看