hihocoder #1328 : 逃离迷宫

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi正处在由 N × M 个房间组成的矩阵迷宫中。为了描述方便,我们把左上角的房间的坐标定为(0, 0),右下角房间的坐标定为(N-1, M-1)。每个房间可能是3种状态之一:开放的、关闭的、或者上锁的。

开放房间用'.'表示。小Hi可以从一个开放房间到达另一个相邻的(上下左右)开放房间。

关闭房间用'#'表示。小Hi永远不能进入一个关闭的房间。

上锁的房间用大写字母('A', 'B', 'C' ...)表示。小Hi在取得相应的钥匙前不能进入上锁的房间,而一旦取得钥匙就可以反复进入上锁的房间。每个房间的锁都是不同的,相应的钥匙在迷宫中的某一房间里,小Hi进入该房间就可以取得钥匙。

小Hi一开始处于一个开放房间,坐标(ab)。迷宫的出口是一个开放或者上锁的房间,坐标(cd)。假设小Hi每移动到一个相邻房间需要花费单位1的时间,那么小Hi到达出口最少需要花费多少时间?

输入

第一行包含7个整数: N , M , K , a , b , c , d . 其中N , M是矩阵的行列数;K 是上锁的房间数目,(ab)是起始位置,(cd)是出口位置。(1 ≤ NM ≤ 100, 0 ≤ K ≤ 5, 0 ≤ ac < N, 0 ≤ bd < M)

以下 N 行每行包含 M 个字符,表示迷宫矩阵。

再以下 K 行每行两个整数 xy,依次表示上锁房间A , B , C ....的钥匙所在房间坐标。(0 ≤ x < N, 0 ≤ y < M)

输出

输出到达出口的最短时间。如果小Hi永远到达不了出口,输出-1。

样例输入
4 4 2 0 0 0 3
.A.B
.#..
.#..
.#..
3 0
3 3 
样例输出
15
思路:状态压缩。用v[x][y][k]表示在(x,y)这个点是否访问过,k的二进制表示现在身上有多少个钥匙。

#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
struct lenka
{
	int x,y,sum;
}key[10];
char s[105][105];
int v[105][105][1<<6];
int d[4][2]={-1,0,0,-1,1,0,0,1};
int n,m,ex,ey;
int bfs(int nx,int ny)
{
	memset(v,0,sizeof v);
	v[nx][ny][0]=1;
	queue<struct lenka>p;
	p.push((lenka){nx,ny,0});
	while(!p.empty())
	{
		lenka now=p.front();p.pop();
		if(now.x==ex&&now.y==ey)return v[now.x][now.y][now.sum]-1;
		for(int i=0;i<4;i++)
		{
			nx=now.x+d[i][0];
			ny=now.y+d[i][1];
			if(nx>=0&&nx<n&&ny>=0&&ny<m&&s[nx][ny]!='#')
			{
				if(s[nx][ny]=='.'&&v[nx][ny][now.sum]==0)
				{
					v[nx][ny][now.sum]=v[now.x][now.y][now.sum]+1;
					p.push((lenka){nx,ny,now.sum});
				}
				else if('0'<=s[nx][ny]&&s[nx][ny]<='5')
				{
					int sum=now.sum|(1<<(s[nx][ny]-'0'));
					if(v[nx][ny][sum])continue;
					v[nx][ny][sum]=v[now.x][now.y][now.sum]+1;
					p.push((lenka){nx,ny,sum});
				}
				else if(s[nx][ny]>='A'&&s[nx][ny]<='Z')
				{
					if(now.sum&(1<<(s[nx][ny]-'A'))&&v[nx][ny][now.sum]==0)
					{
						v[nx][ny][now.sum]=v[now.x][now.y][now.sum]+1;
						p.push((lenka){nx,ny,now.sum});
					}
				}
			}
		}
	}
	return -1;
}
int main()
{
	int sx,sy,T;
	scanf("%d%d%d%d%d%d%d",&n,&m,&T,&sx,&sy,&ex,&ey);
	for(int i=0;i<n;i++)scanf("%s",s[i]);
	for(int i=0;i<T;i++)
	{
		scanf("%d%d",&key[i].x,&key[i].y);
		s[key[i].x][key[i].y]='0'+i;
	}
	printf("%d\n",bfs(sx,sy));
	return 0;
}




### 关于编号为1027的逃离迷宫问题 #### 题目描述 在一个由 `n` 行 `m` 列组成的二维网格中,有一个机器人位于左上角的位置 `(0, 0)`。该机器人的目标是移动到右下角位置 `(n-1, m-1)` 的出口处。每次可以向上、向下、向左或向右移动一步,但不能走出边界。某些格子可能是障碍物,无法通行。 给定一个表示迷宫的地图矩阵 `maze[n][m]`,其中 `0` 表示可以通过的空间,`1` 表示不可通过的墙壁或障碍物。求解是否存在一条路径可以从起点到达终点,并返回这条路径上的坐标序列;如果不存在这样的路径,则输出相应提示信息[^1]。 #### 解决方案概述 为了找到从起始点至终止点的有效路径,可采用广度优先搜索 (BFS) 或者深度优先搜索 (DFS)[^2] 来遍历整个地图空间。这两种方法都是图论中的经典算法,在处理连通性和最短路等问题上有广泛应用价值。对于本题而言: - **初始化**:创建队列并将初始节点加入队列; - **循环条件**:当队列不为空时继续执行; - **扩展状态**:取出当前节点并标记已访问过,尝试沿四个方向探索相邻未被访问过的有效邻居节点; - **结束标志**:一旦触及目的地即刻停止搜索过程,记录成功轨迹;反之则报告失败情况。 ```python from collections import deque def escape_maze(maze): n = len(maze) m = len(maze[0]) # 定义四个可能的方向 directions = [(0, 1), (1, 0), (-1, 0), (0, -1)] queue = deque([((0, 0), [])]) # ((当前位置y,x),(经过的路径)) visited = set([(0, 0)]) while queue: pos, path = queue.popleft() if pos == (n-1, m-1): # 如果已经到了终点 return ["Path found:", *path, "(%d,%d)" % pos] for dy, dx in directions: ny, nx = pos[0]+dy, pos[1]+dx if not (0 <= ny < n and 0 <= nx < m) or maze[ny][nx] != 0 or (ny,nx) in visited: continue new_path = list(path) new_path.append("(%d,%d)"%(pos[0],pos[1])) queue.append(((ny, nx), new_path)) visited.add((ny, nx)) return [&#39;No Path Found&#39;] ``` 此代码实现了上述提到的方法来查找迷宫内的逃生路线。它利用了一个双端队列来进行层次化地逐层展开搜索操作,从而保证最先发现的目标就是距离最近的一条可行径[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值