题意
去年秋天,农夫约翰带着奶牛们参观了一个玉米迷宫。但这不是一个普通的玉米迷宫:它有几个重力驱动的传送滑梯,可以让奶牛瞬间从迷宫中的一个点传送到另一个点。滑梯是双向的:奶牛可以瞬间从滑梯的起点滑到终点,或者从终点滑到起点。如果奶牛踩到滑梯的任一端,她必须使用滑梯。
玉米迷宫的外部完全由玉米包围,只有一个出口。
迷宫可以用一个 N × M N \times M N×M( 2 ≤ N ≤ 300 2 \leq N \leq 300 2≤N≤300; 2 ≤ M ≤ 300 2 \leq M \leq 300 2≤M≤300)的网格表示。每个网格元素包含以下元素之一:
- 玉米(不可通行)
- 草地(可以通行)
- 滑梯端点(会将奶牛传送到另一个端点)
- 出口
奶牛只能从一个空间移动到相邻的下一个空间,前提是它们相邻且都不包含玉米。每个草地空间有四个潜在的邻居可以让奶牛到达。从一个草地空间移动到相邻空间需要 1 1 1 个时间单位;从一个滑梯端点移动到另一个端点需要 0 0 0 个时间单位。
填满玉米的空间用井号(#
)表示。草地空间用英文句号(.
)表示。滑梯端点对用相同的大写字母(A
到 Z
)表示,并且没有两个不同的滑梯端点用相同的字母表示。出口用等号(=
)表示。
贝茜迷路了。她知道自己在网格中的位置,并用「at」符号(@
)标记了她当前的草地空间。她需要的最短时间是多少才能移动到出口空间?
输入格式
第一行:两个用空格隔开的整数 N N N 和 M M M。
第 2 ∼ N + 1 2 \sim N+1 2∼N+1 行:第 i + 1 i+1 i+1 行描述了迷宫中的第 i i i 行的情况(共有 M M M 个字符,每个字符之间没有空格)。
输出格式
一个整数,表示起点到出口所需的最短时间。
思路
简单BFS即可,无需过多解释。
注意几个比较坑的地方:
-
判断传送门端点必须同时判断横纵坐标(也就是说传送门两端可能在同一行或同一列),否则你会收获79分,详见 feng_chenShy 的帖子。
-
传送门可能不止使用一次,如以下情况:
7 10
###...####
=..###...#
#..#######
#.A#.B#.C#
##########
#....ABC@#
##########
具体可参考buzhidao 的帖子。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
char mp[305][305];
bool vis[305][305];
queue<int>x,y,t;
struct point{
int x_a = 0,y_a = 0;
int x_b = 0,y_b = 0;
}P[30];
void g(int p,int q) {
//printf("_____%d %d\n",p,q);
if(mp[p][q] >= 'A' and mp[p][q] <= 'Z') {
int W = int(mp[p][q] - 'A');
if(P[W].x_a == p and P[W].y_a == q) {
x.push(P[W].x_b),y.push(P[W].y_b),t.push(t.front() + 1);
}
else x.push(P[W].x_a),y.push(P[W].y_a),t.push(t.front() + 1);
return;
}
if(vis[p][q] == 0) {
vis[p][q] = 1;
x.push(p),y.push(q),t.push(t.front() + 1);
}
}
signed main() {
scanf("%d %d",&n,&m);
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= m;j++) {
cin>>mp[i][j];
if(mp[i][j] == '#') vis[i][j] = 1;
else if(mp[i][j] == '@') x.push(i),y.push(j),t.push(0),vis[i][j] = 1;
else if(mp[i][j] >= 'A' and mp[i][j] <= 'Z') {
if(P[int(mp[i][j] - 'A')].x_a == 0) {
P[int(mp[i][j] - 'A')].x_a = i;
P[int(mp[i][j] - 'A')].y_a = j;
}
else {
P[int(mp[i][j] - 'A')].x_b = i;
P[int(mp[i][j] - 'A')].y_b = j;
}
}
}
}
while(!x.empty()) {
int x_fi = x.front(),y_fi = y.front();
//printf("%d %d %d\n",x_fi,y_fi,t.front());
if(mp[x_fi][y_fi] == '=') {
printf("%d\n",t.front());
return 0;
}
if(x_fi + 1 <= n) g(x_fi + 1,y_fi);
if(y_fi - 1 >= 1) g(x_fi,y_fi - 1);
if(x_fi - 1 >= 1) g(x_fi - 1,y_fi);
if(y_fi + 1 <= m) g(x_fi,y_fi + 1);
x.pop(),y.pop(),t.pop();
}
return 0;
}