迷宫寻路

问题描述:


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

输入描述:
迷宫的地图,用二维矩阵表示。第一行是表示矩阵的行数和列数M和N
后面的M行是矩阵的数据,每一行对应与矩阵的一行(中间没有空格)。M和N都不超过100, 门不超过10扇。
输出描述:
路径的长度,是一个整数
示例1
输入:
5 5
02111
01a0A
01003
01001
01111

输出
7

思路:

借鉴别人的思路,超蓝の悟空,用广度优先搜索bfs遍历每个可能的位置,当到达终点时可以确定是最短路径。

关键的一步是判断下一个位置是否是可到达的,若可到达,则将该位置加入队列中。

book[x][y][key]的意义就是 横坐标为x,纵坐标为y,钥匙状态为key的点是否访问过。

#include<stdio.h>
#include<queue>
#include<string.h>
#include<vector>
using namespace std;
char G[105][105];
int book[105][105][1200], N, M;
int Next[4][2] = { 0,1,0,-1,1,0,-1,0 };
int bfs(int, int);
struct node {
	int x, y, k, step;
	node(int x, int y, int k, int step) :x(x), y(y), k(k), step(step) {}
};
int main() {
	int i, j;
	//freopen("input.txt","r",stdin);
	while (scanf("%d%d", &N, &M) != EOF) {
		for (i = 0; i<N; i++) scanf("%s", G[i]);
		memset(book, 0, sizeof(book));
		
		for (i = 0; i<N; i++) {
			for (j = 0; j<M; j++)
				if (G[i][j] == '2') {
					book[i][j][0] = 1;
					printf("%d\n", bfs(i, j));
					break;
				}
		}
	}
}
int bfs(int startX, int startY) {
	queue<node> Q;
	Q.push(node(startX, startY, 0, 0));
	while (!Q.empty()) {
		node head = Q.front(); Q.pop();
		if (G[head.x][head.y] == '3') 
            return head.step;
		for (int i = 0; i<4; i++) {
			int nx = head.x + Next[i][0], ny = head.y + Next[i][1];
			if (nx >= N || nx<0 || ny >= M || ny<0 || G[nx][ny] == '0') 
                continue;
			int key = head.k;
			if ('a' <= G[nx][ny] && G[nx][ny] <= 'z') 
                key = key | (1 << (G[nx][ny] - 'a'));
			if ('A' <= G[nx][ny] && G[nx][ny] <= 'Z' && (key&(1 << (G[nx][ny] - 'A'))) == 0) 
                continue;
			if (!book[nx][ny][key]) {
				book[nx][ny][key] = 1;
				Q.push(node(nx, ny, key, head.step + 1));
			}
		}
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值