#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、解题思路
问题要求解从左上角的点到右下角的点的最短路径,并输出。要求解最短路径,可以用广度优先搜索,因为广度优先搜索具有最佳解的性质:若所有边的长度相等,广度优先搜索算法是最佳解——亦即它找到的第一个解,距离根节点的边数目一定最少。因为这题要求输出走过的路径,所必须在搜索的过程中记录下路径。
广度优先搜索的具体做法
因为我们需要输出路径,所以在进行广度优先搜索时并没有采用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<>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<<"("<