迷宫问题(POJ3984)

POJ3984

1、问题描述

POJ地址

定义一个二维数组:

int maze[5][5] = {

    0, 1, 0, 0, 0,

    0, 1, 0, 1, 0,

    0, 0, 0, 0, 0,

    0, 1, 1, 1, 0,

    0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output
左上角到右下角的最短路径,格式如样例所示。

Sample Input
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

2、解题思路

问题要求解从左上角的点到右下角的点的最短路径并输出。要求解最短路径,可以用广度优先搜索,因为广度优先搜索具有最佳解的性质:若所有边的长度相等,广度优先搜索算法是最佳解——亦即它找到的第一个解,距离根节点的边数目一定最少。因为这题要求输出走过的路径,所必须在搜索的过程中记录下路径

广度优先搜索的具体做法

  1. 从初始节点start开始,将start加入队列
  2. 取出队列中的队头元素,访问以该节点为起始点的四个邻域节点,,这里需要判断该节点是否可访问(maps[i][j]==0),是否已经被访问过(visited[i][j]==0),同时检查该节点是否超出地图越界。
  3. 如果经过检查后该节点可以访问,则访问该节点,visited[i][j]=1,并将该节点的信息(横坐标x,纵坐标y,父节点f)存入队列中。
  4. 重复2步骤,直到找到end节点,或者队列为空。

因为我们需要输出路径,所以在进行广度优先搜索时并没有采用STL里的queue,因为如果使用STL里的队列,队头元素出队后就真正地丢失了这个节点的信息,所以具体做法是自己用数组模拟队列,队列中存储一个节点的信息,包括:节点横坐标,纵坐标,父节点。

3、具体实现时用到的存储

int maps[R][C];

定义一个二维数组maps存储地图,数组中1表示该点有墙,不可访问。

int visited[R][C];

定义一个二维数组存储地图上各点是否被访问过。

typedef struct node
{
    int x;
    int y;
    int f;

    node(int x = -1, int y = -1 , int f = -1 )
    {
        this->x = x;
        this->y = x;
        this->f = f;
    }
}Node;

用一个节点Node存储搜索过程中的路径信息,x,y分别表示该节点在地图maps中的下标位置,f当前节点是从哪一个节点搜索过来的,也就是当前节点的父亲。

模拟队列

typedef struct myqueue
{
    Node list[30];//存放搜索过程的节点
    int head;//指示list数组中的队头
    int tail;//队尾指针

    myqueue()//默认构造函数
    {
        head = 0;
        tail = 0;
    }
    void push(Node & n1)//节点n1入队
    {
        list[tail] = n1;
        tail++;
    }

    Node getHead()//返回队列的头结点
    {
        return list[head];
    }

    void pop()//队首元素出队
    {
        head++;
    }
    bool isEmpty()//队列是否为空,队列为空返回true,否则返回false
    {
        if(head==tail)//
            return true;
        else
            return false;
    }
}Myqueue;

4、程序

注意:为了便于输出在调用BFS时将终点和起点的位置调换了。

#include "iostream"
using namespace std;

const int R = 5;
const int C = 5;

int maps[R][C];
int visited[R][C];

typedef struct node
{
    int x;
    int y;
    int f;

    node(int x = -1, int y = -1 , int f = -1 )
    {
        this->x = x;
        this->y = x;
        this->f = f;
    }
}Node;

typedef struct myqueue
{
    Node list[30];
    int head;
    int tail;

    myqueue()
    {
        head = 0;
        tail = 0;

    }
    void push(Node & n1)//节点n1入队
    {
        list[tail] = n1;
        tail++;
    }

    Node getHead()//返回队列的头结点
    {
        return list[head];
    }

    void pop()//队首元素出队
    {
        head++;
    }
    bool isEmpty()//队列是否为空,队列为空返回true,否则返回false
    {
        if(head==tail)
            return true;
        else
            return false;
    }
}Myqueue;

bool isValied(int x, int y)//判断以x,y为横纵坐标的访问是否合法
{
    if(x>=0 && y>=0 && x<=4 && y<=4 && visited[x][y] == 0 && maps[x][y] == 0)
        return true;
    else
        return false;
}

bool equal(Node n1, Node n2)//判断两个节点是否相等。
{
    if(n1.x==n2.x && n1.y==n2.y)
        return true;
    else
        return false;
}

int BFS(Myqueue & q, Node start, Node end)//对maps地图以start为起始点,end为终止节点进行广度优先搜索,
{                                         //函数返回最后一个end节点在队列数组list中的下标。
    q.push(start);
    while(!q.isEmpty())
    {

        Node t = q.getHead();//从队头取元素
        //cout<<t.x<<" "<<t.y<<endl;// 4 4
        // Node left(t.x, t.y-1, q.head);//??
        Node left;
        left.x = t.x;
        left.y = t.y-1;
        left.f = q.head;//队头元素为其左节点的父节点,此时q.head为队头元素在list数组中的下标。

        Node right;
        right.x = t.x;
        right.y = t.y+1;
        right.f = q.head;

        Node up;
        up.x = t.x-1;
        up.y = t.y;
        up.f = q.head;

        Node down;
        down.x = t.x+1;
        down.y = t.y;
        down.f = q.head;

        if(isValied(left.x,left.y))//访问
        {
            visited[left.x][left.y] = 1;
            q.push(left);
            if(equal(left, end))
                return q.tail-1;
        }
        if(isValied(up.x,up.y))
        {
            visited[up.x][up.y] = 1;
            q.push(up);
            if(equal(up, end))
                return q.tail-1;
        }
        if(isValied(right.x,right.y))
        {
            visited[right.x][right.y] = 1;
            q.push(right);
            if(equal(right, end))
                return q.tail-1;
        }
        if(isValied(down.x,down.y))
        {
            visited[down.x][down.y] = 1;
            q.push(down);
            if(equal(down, end))
                return q.tail-1;
        }
        q.pop();
    }
    return -1;
}

int main()
{
    for(int i=0;i<R;i++)
        for(int j=0;j<C;j++)
        {
            cin>>maps[i][j];
            visited[i][j] = maps[i][j];
        }
    Myqueue q;
    Node start(4,4,-1);//为了输出路径方便,将终点和起点的位置对换,这样输出路线时就像链表一样操作
    Node end(0,0,-1);

    int index = BFS(q, start, end);

    while(q.list[index].f != -1)//等于-1时说明找到了start节点,也就是到达了(4, 4)点,此时还没输出该点
    {
        cout<<"("<<q.list[index].x<<", "<<q.list[index].y<<")"<<endl;
        index = q.list[index].f;
    }
    cout<<"("<<q.list[index].x<<", "<<q.list[index].y<<")";
}
    原文作者:迷宫问题
    原文地址: https://blog.csdn.net/ha_ha_ha233/article/details/80516489
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞