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)\n",6,8);
        
    }
    
    
    return 0;
}
posted @ 2014-09-09 09:54  hessen  阅读(6277)  评论(0编辑  收藏  举报