bfs 最短路径的计算和打印 迷宫——蓝桥p602

目录

前言

  相邻节点距离相同

   相邻节点距离不同

   打印路径

迷宫

   问题描述

  输入

   输出

问题分析

   打印节点方法

   剪枝

代码


前言

        求最短路径是一个典型的图论问题,但它也分为两种情况

  相邻节点距离相同

        由于bfs本身的搜索方式就是一圈一圈向外扩展,这个问题用普通的bfs就行了,因为最先扩展到的到达终点的路径肯定就是最短路

   相邻节点距离不同

        由于相邻节点距离不同此时就不能用常规的bfs,这会导致不同的方向扩散的距离不同,这就要使用dijkstra算法(每次先入队距离最短的路径)或其他更加通用的算法

   打印路径

        由于在一个图论问题中,最短路往往不是唯一的,所以一般不会要求打印路径,如果要打印,一般是打印字典序最小的路

迷宫

   问题描述

        给定一个迷宫,入口为左上角,出口为右下角,用一个30*50的数字网格代表迷宫,其中1表示障碍,0表示平地,要求只能上下左右一格一格在平地上移动,请找出一种路径最短的离开迷宫的方式,如果有多种答案,输出字典序最小的一种

  输入

        输入一格30*50的迷宫

   输出

        输出字典序最少,且路径最短的一种路径

备注:字典序中D<L<R<U

问题分析

        本题是一个相邻节点距离相同的图论问题,所以用普通的bfs就可以完成,但是本题需要打印最短路径,所以需要一个数组pre[x][y]存储节点(x,y)的前驱节点。

   打印路径方法

        首先我们解决一下打印路径方法的问题,上面说到用一个数组pre[x][y]存储节点(x,y)的前驱节点,但存储一格节点数组太浪费空间,在这里我们这样处理,pre[x][y]=上一节点到达该节点的方法。例如:

这样我们就知道,(2,3)这个节点是由其前一个节点左移一格而来的,那么我们就可以很快得到(2,3)的前驱就是(2,4),然后再利用递归思想到(0,0)结束递归,就可以得出完整路径。

   剪枝

        明确的这点之后就可以进行剪枝了,由于本题相对简单,所以剪枝也就是只有两个常规剪枝,可行性剪枝,最优化剪枝

代码

#include<iostream>
#include<queue>
using namespace std;

char pre[40][60];
char mp[40][60];
bool vis[40][60];
int dir[5][2] = { {0,0}, { 1,0 },{0,-1},{0,1},{-1,0} };
char pos[5] = { 'O','D','L','R','U' };
struct node {
	int x;
	int y;
	node() {}
	node(int xx,int yy):x(xx),y(yy){}
};

queue<node>que;
node now, nxt;

void print_path(int x, int y) {
	if (x == 1 && y == 1) return;
	if (pre[x][y] == 'D') print_path(x - 1, y);
	if (pre[x][y] == 'L') print_path(x, y + 1);
	if (pre[x][y] == 'R') print_path(x, y - 1);
	if (pre[x][y] == 'U') print_path(x + 1, y);
	cout << pre[x][y];  //相当于二叉树的后序遍历,会将最后入栈的元素(起点)最先打印
}

void bfs() {
	que.push(node(1, 1));
	vis[0][0] = true;
	while (!que.empty()) {
		now = que.front();
		if (now.x == 30 && now.y == 50) {
			print_path(30, 50);
		}
		que.pop();
		for (int i = 1; i <= 4; i++) {
			int nx = now.x + dir[i][0], ny = now.y + dir[i][1];
			if (nx < 1 || nx>30 || ny < 1 || ny>50 || mp[nx][ny]=='1') continue; //剪枝1
			if (!vis[nx][ny]) { //剪枝2
				vis[nx][ny] = true;
				que.push(node(nx, ny));
				pre[nx][ny] = pos[i];
			}
		}
	}
}

int main() {
	for (int i = 1; i <= 30; i++) {
		for (int j = 1; j <= 50; j++) {
			cin >> mp[i][j];
		}
	}
	bfs();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值