神殿

本文介绍了一种使用广度优先搜索(BFS)算法解决迷宫寻路问题的方法,通过构建矩阵表示房间和门的存在状态,实现了从起点到终点的最短路径寻找。文章详细解析了算法流程,包括如何处理房间旋转和路径选择,以及如何通过代码实现这一过程。

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

神殿

题目大意

在这里插入图片描述
用一个n∗mn∗mnm的矩阵,矩阵的每一个点都是一个房间,房间只有某些方向有门(见上图),要从一个房间走向相邻的房间必须要他们中间的两个门都是存在,也可以把所有房间的门顺时针旋转一轮。

走到相邻的房间要一个单位时间,旋转房间门也要一个时间单位。
现在问从(x1,y1)(x_1,y_1)(x1,y1)走到(x2,y2)(x_2,y_2)(x2,y2)最少需要多少各单位时间。

样例输入1

2 2
+*
*U
1 1 2 2

样例输出1

-1

样例输入2

2 3
<><
><>
1 1 2 1

样例输出2

4

数据范围

在这里插入图片描述

思路

这道题我们用bfsbfsbfs来做。
其实就是分为走到旁边的房间和旋转两种,具体看代码吧。

代码

#include<cstdio>
#include<queue>
using namespace std;
int n,m,x1,y1,x2,y2,dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool a[1501][1501][5],in[1501][1501][5];
char c;
struct note
{
	int x,y,t,turn;
};
int abs(int x)
{
	while (x<0) x=4+x;
	return x;
}
void bfs()//bfs
{
	queue<note>l;//建队列
	l.push((note){x1,y1,0,0});//加入队列
	in[x1][y1][0]=1;//标记
	if (x1==x2&&y1==y2)//有没有到终点
	{
		printf("0");//输出
		return ;//找到终点就可以退出了
	}
	while (l.size())
	{
		note x=l.front();//取出
		l.pop();//用完就可以扔掉了
		for (int i=0;i<4;i++)//枚举每一个走的方向
		 if (!in[x.x+dx[i]][x.y+dy[i]][x.turn])//是否没有走过
		  if (a[x.x][x.y][abs(i-x.turn)%4]&&a[x.x+dx[i]][x.y+dy[i]][abs(i-x.turn+2)%4])//是否中间的两个门都存在
		   if(x.x+dx[i]>0&&x.x+dx[i]<=n&&x.y+dy[i]>0&&x.y+dy[i]<=m)//是否超界
			{
		 		note y;
		 		y.x=x.x+dx[i];//走到那个房间
		 		y.y=x.y+dy[i];
		 		y.t=x.t+1;//所需时间+1
		 		y.turn=x.turn;//房间转的次数不变
		 		in[y.x][y.y][y.turn]=1;//标记
		 		l.push(y);//加入队列
		 		if (y.x==x2&&y.y==y2)//是否到了终点
		 		{
		 			printf("%d",y.t);//输出
		 			return ;//找到终点就可以退出了
				}
			}
		if (!in[x.x][x.y][(x.turn+1)%4])//旋转
		{
			note y;
			y.x=x.x;//房间不变
			y.y=x.y;
			y.t=x.t+1;//所需时间+1
			y.turn=(x.turn+1)%4;//房间转的次数+1
			in[y.x][y.y][y.turn]=1;//标记
		 	l.push(y);//加入队列
		 	if (y.x==x2&&y.y==y2)//是否到了终点
		 	{
		 		printf("%d",y.t);//输出
		 		return ;//找到终点就可以退出了
			}
		}
	}
	printf("-1");//如果没有到就退出了,那么就说明找不到,输出-1
}
int main()
{
//	freopen("temple.in","r",stdin);
//	freopen("temple.out","w",stdout);
	scanf("%d%d",&n,&m);//读入
	for (int i=1;i<=n;i++)
	{
		getchar();//处理换行符
		for (int j=1;j<=m;j++)
		{
			c=getchar();//读入
			if (c=='+')//打表
			{
				a[i][j][0]=1;
				a[i][j][1]=1;
				a[i][j][2]=1;
				a[i][j][3]=1;
			}
			else if (c=='-')//打表
			{
				a[i][j][1]=1;
				a[i][j][3]=1;
			}
			else if (c=='|')//打表
			{
				a[i][j][0]=1;
				a[i][j][2]=1;
			}
			else if (c=='^')//打表
			{
				a[i][j][0]=1;
			}
			else if (c=='>')//打表
			{
				a[i][j][1]=1;
			}
			else if (c=='v')//打表
			{
				a[i][j][2]=1;
			}
			else if (c=='<')//打表
			{
				a[i][j][3]=1;
			}
			else if (c=='L')//打表
			{
				a[i][j][0]=1;
				a[i][j][1]=1;
				a[i][j][2]=1;
			}
			else if (c=='R')//打表
			{
				a[i][j][0]=1;
				a[i][j][2]=1;
				a[i][j][3]=1;
			}
			else if (c=='U')//打表
			{
				a[i][j][1]=1;
				a[i][j][2]=1;
				a[i][j][3]=1;
			}
			else if (c=='D')//打表
			{
				a[i][j][0]=1;
				a[i][j][1]=1;
				a[i][j][3]=1;
			}
		}
	}
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);//读入
	bfs();//bfs
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值