【牛客网】迷宫寻路

题目描述

假设一个探险家被困在了地底的迷宫之中,要从当前位置开始找到一条通往迷宫出口的路径。迷宫可以用一个二维矩阵组成,有的部分是墙,有的部分是路。迷宫之中有的路上还有门,每扇门都在迷宫的某个地方有与之匹配的钥匙,只有先拿到钥匙才能打开门。请设计一个算法,帮助探险家找到脱困的最短路径。如前所述,迷宫是通过一个二维矩阵表示的,每个元素的值的含义如下 0-墙,1-路,2-探险家的起始位置,3-迷宫的出口,大写字母-门,小写字母-对应大写字母所代表的门的钥匙

输入描述:

迷宫的地图,用二维矩阵表示。第一行是表示矩阵的行数和列数M和N
后面的M行是矩阵的数据,每一行对应与矩阵的一行(中间没有空格)。M和N都不超过100, 门不超过10扇。

输出描述:

路径的长度,是一个整数

解题思路有两个要点:

  • (1)采用广度优先遍历。深度优先遍历会暴栈。
  • (2)需要标记已访问的节点,访问的节点标记时候不仅包含坐标,还包含某个节点的钥匙状态(即访问到该节点时拥有两把钥匙和拥有一把钥匙的状态是不一样的,需要分别标记)。使用int的位来存储钥匙状态,用位运算符来判断钥匙状态。比如:

只拥有钥匙a,二进制位为0001,整数表示为1

拥有钥匙a和钥匙b,二进制位为0011,整数表示为3

每个bit位表示拥有一把钥匙!

AC代码如下

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

int offset[4][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
int book[100][100][1024] = {0};

struct node{
	int x, y, key, step;
	node(int x, int y, int key, int step):x(x), y(y), key(key), step(step){}
};

int bfs(vector<string> maze, int x, int y)
{
	queue<node> Q; Q.push(node(x, y, 0, 0));
	while (!Q.empty())
	{
		node h = Q.front(); Q.pop();
		if(maze[h.y][h.x] == '3') return h.step;
		for (int i = 0; i < 4; i++)
		{
			int nx = h.x + offset[i][0], ny = h.y + offset[i][1];
			if(nx < 0 || nx >= maze[0].size() || ny < 0 || ny >= maze.size() || maze[ny][nx] == '0') continue;
			int keyState = h.key;
			if(maze[ny][nx] >= 'a' && maze[ny][nx] <= 'z') keyState |= (1 << (maze[ny][nx] - 'a'));//捡钥匙
			if(maze[ny][nx] >= 'A' && maze[ny][nx] <= 'Z' && (keyState & (1 << (maze[ny][nx] - 'A'))) == 0) 
				continue; //没有打开门的钥匙
			if(!book[ny][nx][keyState])
			{
				book[ny][nx][keyState] = 1;
				Q.push(node(nx, ny, keyState, h.step + 1));
			}
		}
	}
	return 0;
}

int main()
{
    int m, n;
    vector<string> mp;//存储迷宫
    cin >> m >> n;
    while(m--)
    {
        string s;
        cin >> s;
        mp.push_back(s);
    }
	int flag = 0;
    for(int j = 0; j < mp.size(); j++)
    {
        for(int i = 0; i < n; i++)
        {
            if(mp[j][i] == '2')
			{
				flag = 1;
				book[j][i][0] = 1;
				cout << bfs(mp, i, j) << endl;
				break;
			}
        }
		if(1 == flag) break;
    }
 
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值