题解:洛谷 P1825 [USACO11OPEN] Corn Maze S

【题目来源】

洛谷:[P1825 USACO11OPEN] Corn Maze S - 洛谷

【题目描述】

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

传送操作不能连续使用,即,传送一次之后,必须通过非传送方式移动至少一步才能再次进行传送。

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

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

  • 玉米(玉米网格元素不可通行)
  • 草地(容易通过!)
  • 滑梯端点(会将奶牛传送到另一个端点)
  • 出口

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

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

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

【输入】

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

\(2 \sim N+1\) 行:第 \(i+1\) 行描述了迷宫中的第 \(i\) 行的情况(共有 \(M\) 个字符,每个字符之间没有空格)。

【输出】

一个整数,表示起点到出口所需的最短时间。

【输入样例】

5 6
###=##
#.W.##
#.####
#.@W##
######

【输出样例】

3

【解题思路】

image

【算法标签】

《洛谷 P1825 Corn Maze》 #模拟# #搜索# #广度优先搜索,BFS# #最短路# #USACO# #2011#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int n, m;  // 地图的行数和列数
// 四个方向的偏移量:上、下、左、右
int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
char a[305][305];  // 存储地图
char tmp;          // 临时字符变量

// 定义位置结构体,包含坐标和步数
struct node 
{
    int x, y, step;
};

// 定义传送门结构体,记录两个端点的坐标
struct mark 
{
    int x1, y1, x2, y2;
} cs[100];  // 最多26个字母的传送门

int main()
{
    // 输入地图尺寸
    cin >> n >> m;
    
    // 初始化BFS队列
    queue<node> q;
    
    // 读取地图数据
    for (int i = 1; i <= n; i++) 
    {
        for (int j = 1; j <= m; j++) 
        {
            cin >> a[i][j];
            tmp = a[i][j];
            
            // 如果是传送门(A-Z)
            if (tmp >= 'A' && tmp <= 'Z') 
            {
                // 记录传送门的两个端点
                if (cs[tmp].x1 == 0) 
                {
                    cs[tmp].x1 = i;
                    cs[tmp].y1 = j;
                } 
                else 
                {
                    cs[tmp].x2 = i;
                    cs[tmp].y2 = j;
                }
            }
            
            // 如果是起点
            if (tmp == '@') 
            {
                node tp = {i, j, 0};  // 初始步数为0
                q.push(tp);
                a[i][j] = '#';       // 标记为已访问
            }
        }
    }
    
    // BFS主循环
    while (!q.empty()) 
    {
        node tp = q.front();    
        q.pop();
        
        // 尝试四个方向移动
        for (int i = 0; i < 4; i++) 
        {
            int xx = tp.x + dx[i];
            int yy = tp.y + dy[i];
            
            // 检查边界
            if (xx < 1 || xx > n || yy < 1 || yy > m) continue;
            
            // 如果是障碍物
            if (a[xx][yy] == '#') continue;
            
            // 如果是可通行的空地
            if (a[xx][yy] == '.') 
            {
                node t = {xx, yy, tp.step + 1};
                q.push(t);
                a[xx][yy] = '#';  // 标记为已访问
                continue;
            }
            
            // 如果是终点
            if (a[xx][yy] == '=') 
            {
                cout << tp.step + 1;  // 输出步数
                return 0;
            }
            
            // 如果是传送门
            if (cs[a[xx][yy]].x1 == xx && cs[a[xx][yy]].y1 == yy) 
            {
                // 传送到另一端
                node t = {cs[a[xx][yy]].x2, cs[a[xx][yy]].y2, tp.step + 1};
                q.push(t);
            } 
            else 
            {
                // 传送到另一端
                node t = {cs[a[xx][yy]].x1, cs[a[xx][yy]].y1, tp.step + 1};
                q.push(t);
            }
        }
    }
    
    return 0;
}

【运行结果】

5 6
###=##
#.W.##
#.####
#.@W##
######
3
posted @ 2026-02-17 19:34  团爸讲算法  阅读(9)  评论(0)    收藏  举报