【BFS/思维】P1825 [USACO11OPEN] Corn Maze S

题意

去年秋天,农夫约翰带着奶牛们参观了一个玉米迷宫。但这不是一个普通的玉米迷宫:它有几个重力驱动的传送滑梯,可以让奶牛瞬间从迷宫中的一个点传送到另一个点。滑梯是双向的:奶牛可以瞬间从滑梯的起点滑到终点,或者从终点滑到起点。如果奶牛踩到滑梯的任一端,她必须使用滑梯。

玉米迷宫的外部完全由玉米包围,只有一个出口。

迷宫可以用一个 N × M N \times M N×M 2 ≤ N ≤ 300 2 \leq N \leq 300 2N300 2 ≤ M ≤ 300 2 \leq M \leq 300 2M300)的网格表示。每个网格元素包含以下元素之一:

  • 玉米(不可通行)
  • 草地(可以通行)
  • 滑梯端点(会将奶牛传送到另一个端点)
  • 出口

奶牛只能从一个空间移动到相邻的下一个空间,前提是它们相邻且都不包含玉米。每个草地空间有四个潜在的邻居可以让奶牛到达。从一个草地空间移动到相邻空间需要 1 1 1 个时间单位;从一个滑梯端点移动到另一个端点需要 0 0 0 个时间单位。

填满玉米的空间用井号(#)表示。草地空间用英文句号(.)表示。滑梯端点对用相同的大写字母(AZ)表示,并且没有两个不同的滑梯端点用相同的字母表示。出口用等号(=)表示。

贝茜迷路了。她知道自己在网格中的位置,并用「at」符号(@)标记了她当前的草地空间。她需要的最短时间是多少才能移动到出口空间?

输入格式

第一行:两个用空格隔开的整数 N N N M M M

2 ∼ N + 1 2 \sim N+1 2N+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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值