输入格式
第一行:两个用空格隔开的整数 N 和 M。
第 2∼N+1 行:第 i+1 行描述了迷宫中的第 i 行的情况(共有M个字符,每个字符中间没有空格)。
输出格式
一个整数,表示起点到出口所需的最短时间。
题意翻译
奶牛们去一个 N×M 玉米迷宫,2≤N≤300,2≤M≤300。
迷宫里有一些传送装置,可以将奶牛从一点到另一点进行瞬间转移。这些装置可以双向使用。
如果一头奶牛处在这个装置的起点或者终点,这头奶牛就必须使用这个装置,奶牛在传送过后不会立刻进行第二次传送,即不会卡在传送装置的起点和终点之间来回传送。
玉米迷宫除了唯一的一个出口都被玉米包围。
迷宫中的每个元素都由以下项目中的一项组成:
- 玉米,
#
表示,这些格子是不可以通过的。- 草地,
.
表示,可以简单的通过。- 传送装置,每一对大写字母 A 到 Z 表示。
- 出口,
=
表示。- 起点,
@
表示奶牛能在一格草地上可能存在的四个相邻的格子移动,花费 1 个单位时间。从装置的一个结点到另一个结点不花时间。
输入输出样例
输入 #1复制
5 6 ###=## #.W.## #.#### #.@W## ######输出 #1复制
3说明/提示
例如以下矩阵,N=5,M=6。
###=## #.W.## #.#### #.@W## ######
唯一的一个装置的结点用大写字母 W 表示。
最优方案为:先向右走到装置的结点,花费一个单位时间,再到装置的另一个结点上,花费 0 个单位时间,然后再向右走一个,再向上走一个,到达出口处,总共花费了 3 个单位时间。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,x,y,x2,y2;
char sn[410][410];//存迷宫
int dis[410][410];//存到达某点最短距离
vector<int> e[51];//存传送门
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};//向上下左右移动
void bfs(int a,int b){
queue<pair<int,int> > q;
q.push({a,b});//入队
while(q.size()){
pair<int,int> now=q.front();//取队头
q.pop();//出队
int a=now.first,b=now.second;
for(int i = 0;i<=3;i++){//移动
int xx=a+dx[i],yy=b+dy[i];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&sn[xx][yy]=='.'&&dis[xx][yy]>dis[a][b]+1){
//判断是否越界 是否是草地 是否能得到更短距离
//如果是草地,可以走
q.push({xx,yy});//入队
dis[xx][yy]=dis[a][b]+1;
}
else if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&sn[xx][yy]>='A'&&sn[xx][yy]<='Z'){
//判断是否越界 是否是传送门
//如果是传送门,找到此传送门对应的终点
int d=sn[xx][yy]-'A'+1;//转化为编号
int xx1=e[d][0],yy1=e[d][1],xx2=e[d][2],yy2=e[d][3];
//xx1代表其中一个传送门的横坐标,yy1纵坐标
//xx2代表另一个传送门的横坐标,yy2纵坐标
//下面要注意!!调了好久
if(xx==xx1&&yy==yy1&&dis[xx2][yy2]>dis[a][b]+1){
//如果xx,yy为xx1,yy1这个传送门,那么xx,yy这个点说明没有走到,只有停留才视为走到这个点
//走到的是xx2,yy2这个传送门,可以停留
dis[xx2][yy2]=dis[a][b]+1;
q.push({xx2,yy2});
}else if(xx==xx2&&yy==yy2&&dis[xx1][yy1]>dis[a][b]+1){
//如果xx,yy为xx2,yy2这个传送门,那么xx,yy这个点说明没有走到,只有停留才视为走到这个点
//走到的是xx1,yy1这个传送门,可以停留
dis[xx1][yy1]=dis[a][b]+1;
q.push({xx1,yy1});
}
}
else if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&sn[xx][yy]=='='&&dis[xx][yy]>dis[a][b]+1){
//判断是否到达出口,如果到达,存值并且可以直接结束宽搜
dis[xx][yy]=dis[a][b]+1;
return;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
cin >> sn[i][j];
if(sn[i][j]=='@') x=i,y=j;//记录起点
if(sn[i][j]=='=') x2=i,y2=j;//记录出口
if(sn[i][j]>='A'&&sn[i][j]<='Z'){//记录传送门
int id=sn[i][j]-'A'+1;//将字符转化为编号 例如A编号为1
e[id].push_back(i);
e[id].push_back(j);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dis[i][j]=1e6;//初始化 求最小值
}
}
dis[x][y]=0;//初始化起点距离为0
bfs(x,y);//深搜
cout << dis[x2][y2];
return 0;
}