【补题计划】913模拟赛第一题——maze2

本文介绍了一种利用广度优先搜索(BFS)解决迷宫最短路径问题的方法,包括如何处理门和钥匙等障碍物,实现从起点到终点的最短步数计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先附上原题

迷宫(maze2.pas/c/cpp) TL:1S  ML:128MB 
【Description】 
你所在的迷宫可以用N行M列的矩阵来描述: 
 # 墙,无法通过 
. 地面,可以通过 
小写字母(a、b、c、...、z) 钥匙,可以打开标有对应大写字母的门 
大写字母(A、B、C、...、Z) 门,可以被标有对应小写字母的钥匙打开 
$你的初始位置 
& 迷宫的出口位置 
迷宫的四周都有墙,所以你无法走出这片N*M的区域,只能从”&”处离开迷宫,你只能向东西南北四个方向走。 
你的任务是,计算出走出迷宫需要的最少步数是多少? 
【Input】 
第1行两个正整数N和M,表示迷宫的长和宽;  
第2行一个正整数P,表示门和钥匙的数量; 
第3行至第N+2 行,描述整个迷宫。 
【Output】 
一个整数,为走出迷宫需要的最少步数或-1(如果不可能走出迷宫)。 
【Sample Input】 
5 5 
1 
&A..$
 ####. 
...#. 
.#.#. 
a#... 
【Sample Output】 
28 
【Sample Input】 
1 4 
1 
&aA$

【Sample Output】 
-1 
【Hint】 
对于30%:1 <= N, M <= 15 
另外存在10%:P=0 
另外存在10%:P=1 
另外存在20%:P=2 
对于 100%:1<=N,M<=50,0<=P<=10,保证迷宫中”$”、”&”和所有大小写字母只出现一次,钥匙和门的标号只会出现字母表中的前P个字母。 

这个题可以使用广度优先搜索,依次搜索拿到不同钥匙时走到同一点所需的路程并取最小值。

下面附上代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue> 
using namespace std;
int n,m,p,minlu[51][51][(1<<11)];
char map[51][51];
int nex[4][2]={1,0,-1,0,0,-1,0,1};
struct no
{
	int ax,ay,lu,yao;
};
queue<no> dui;
int main()
{
	freopen("maze2.in","r",stdin); 
	freopen("maze2.out","r",stdout); 
	cin>>n>>m>>p;
	int sx,sy,ex,ey;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			cin>>map[i][j];
			if(map[i][j]=='$')
			{
				sx=i;
				sy=j;
			}
			if(map[i][j]=='&')
			{
				ex=i;
				ey=j;
			}
		}
	no st;
	st.ax=sx;
	st.ay=sy;
	st.lu=0;
	st.yao=0;
	memset(minlu,-1,sizeof(minlu));
	minlu[sx][sy][0]=0;
	dui.push(st);
	no nowe;
	while(!dui.empty())
	{
		nowe=dui.front();
		dui.pop();
		for(int i=0;i<4;i++)
		{
			no now=(no){nowe.ax+nex[i][0],nowe.ay+nex[i][1],nowe.lu+1,nowe.yao};
			if(map[now.ax][now.ay]=='#'||now.ax<1||now.ax>n||now.ay<1||now.ay>m) continue;
			if(map[now.ax][now.ay]>='A'&&map[now.ax][now.ay]<='Z')
				if((now.yao&(1<<(map[now.ax][now.ay]-'A')))==0) continue;
			if(map[now.ax][now.ay]>='a'&&map[now.ax][now.ay]<='z')
				now.yao=(1<<(map[now.ax][now.ay]-'a'))|now.yao;
			if(minlu[now.ax][now.ay][now.yao]==-1||minlu[now.ax][now.ay][now.yao]>now.lu)
			{
		    	minlu[now.ax][now.ay][now.yao]=now.lu;
		    	dui.push(now);
			}
		}
	}
	int ans=~0u>>1;
	for(int i=0;i<(1<<p);i++)
	{
		if(minlu[ex][ey][i]<ans&&minlu[ex][ey][i]!=-1)
		ans=minlu[ex][ey][i];
	}
	if(ans==~0u>>1) ans=-1;
	cout<<ans<<endl;			
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值