迷宫问题(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<<")";
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值