算法竞赛-走迷宫

一个网格迷宫由n行m列的单元格组成,每个单元格要么是空地(用1表示)要么是障碍物
(用0表示)。任务是找一条从起点到终点的最短移动序列,其中UDLR代表上下左右移动到
相邻单元格。任何时候都不能在障碍物格中,也不能走到迷宫之外。起点和终点保证是空地
n,m<=100;


图的bfs与树的bfs一样,但需要避免重复访问一个节点。下面代码用标
记vis[x][y]记录格子(x,y)是否走过,和dfs一样


样例输入:6行5列,入口(0,0),出口(0,4)
6 5      
1 1 0 1 1
1 0 1 1 1
1 0 1 0 0
1 0 1 1 1
1 1 1 0 1

1 1 1 1 1

#include<iostream>
#include<queue>
#include<string>
#include<string>
using namespace std;
const int MAXN = 105;
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };//dx上下,dy左右
char name[] = { 'U','D','L','R' };
int q[MAXN*MAXN];//队列,保存当前结点编号
int vis[MAXN][MAXN], nMap[MAXN][MAXN];
int dir[MAXN*MAXN];
int fa[MAXN][MAXN], dist[MAXN][MAXN], last_dir[MAXN][MAXN];
int n, m;//行、列数

void funInit();
void bfs(int x, int y);
void funcInput();
void print_path(int x,int y);

int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
			cin >> nMap[i][j];
		}
        memset(vis, 0, sizeof(vis));//给初始数组清零
	memset(dist, 0, sizeof(dist));//给初始数组清零
bfs(0,0);//起始点print_path(0, 4);//走出点system("pause");return 0;}void bfs(int x,int y){int front = 0, rear = 0;int u = x*m + y;vis[x][y] = 1;fa[x][y] = u;//起点元素的父亲为它本身dist[x][y] = 0;q[rear++] = u;//第一个元素入队while (front < rear){u = q[front++];//第一个元素出队x = u / m; y = u%m;for (int d = 0; d < 4; d++)//把出队结点上下左右可以访问的元素依次入队{int nx = x + dx[d], ny = y + dy[d];if (nx >= 0 && nx < n&&ny >= 0 && ny < m&&nMap[nx][ny] && !vis[nx][ny])//在数据范围内并且不是障碍且未被访问过{int v = nx*m + ny;q[rear++] = v;//自身入队vis[nx][ny] = 1;//标记为被访问fa[nx][ny] = u;//*********设置当前点的父节点,存入数组中,为接下来寻找路径做准备*********dist[nx][ny] = dist[x][y] + 1;//距离在父节点的基础上加1last_dir[nx][ny] = d;//记录父节点到子节点的移动方向}}}}/*为方便起见我们把格子从上到下编号为0 1 2 3 4 ...n*m,因此第i行第j个格子的编号为i*m+j,而编号为u的行号为u/m,列号为u%m。当格子(x,y)扩展出格子(nx,ny)后,我们不仅需要更新dist[nx][ny]=dist[x][y]+1还要保存新格子(nx,ny)的父亲编号fa[nx][ny]以及父节点到它的移动方向last_dir[nx][ny].有了这两个值,就可把路径打印出来了。*///void print_path(int x,int y)//{// int fx = fa[x][y] / m;// int fy = fa[x][y] % m;// if (fx != x || fy != y)// {// print_path(fx, fy);// putchar(name[last_dir[x][y]]);// }//}/* 这里用到了递归的技巧:如果格子(x,y)有父亲(fx,fy),需要先打印从起点到(fx,fy)的最短路,然后打印(fx,fy)到(x,y)的移动方向,也就是last_dir[x][y]所对应的方向名字。这个函数非常方便,请当心一点:n和m太大时可能会产生栈溢出,需要改写成下面的非递归形式*/void print_path(int x, int y){int c = 0;for (;;){//开始时从指定的点初始 得到fx fy。之后根据该点存储的父节点依次得到其他的fx fy int fx = fa[x][y] / m;int fy = fa[x][y] % m;if (fx == x && fy == y)break;dir[c++] = last_dir[x][y];//把移动方向赋值给数组dir,以便输出路径x = fx;y = fy;}while (c--)putchar(name[dir[c]]);cout << "最短路径长度为:" << dist[0][4] << endl;}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值