惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
有赞技术团队
有赞技术团队
J
Java Code Geeks
H
Hackread – Cybersecurity News, Data Breaches, AI and More
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Check Point Blog
博客园 - 【当耐特】
The GitHub Blog
The GitHub Blog
Recent Announcements
Recent Announcements
The Cloudflare Blog
Microsoft Azure Blog
Microsoft Azure Blog
腾讯CDC
Vercel News
Vercel News
IT之家
IT之家
MyScale Blog
MyScale Blog
博客园_首页
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
罗磊的独立博客

博客园 - katago

【最大子矩形】极大化思想 MobaXterm-Keygen The "vmwgfx unsupported hypervisor" error in VirtualBox with Ubuntu codex 安装必备环境 chatgpt提示词 通过VScode的远程连接 WSL,配置Linux平台python开发环境 扫地机器人基本设计方案 wsl2 安装 SRS + FFmpeg 直播机 拉流推给本机 SRS 的 RTMP P1171 售货员的难题 dfs 状态压缩 + 记忆化搜索 P1171 售货员的难题 for循环状压dp写法 leetcode [698] 划分为k个相等的子集 LeetCode 473. 火柴拼正方形 vscode LeetCode插件安装 LeetCode 464. 我能赢吗 如何找代码bug 八中 搜索作业 线性筛素数计数 atcoder dp基础 八中上机课练习题单 整除分块
P1825 [USACO11OPEN] Corn Maze S
katago · 2026-01-05 · via 博客园 - katago

P1825 [USACO11OPEN] Corn Maze S

题解:

用广度优先搜索(BFS)。每次从队列取出当前格子,向四个方向尝试:

如果是墙或越界,跳过;

如果是普通格子且未访问,标记距离/访问并入队;

如果是大写字母,找到同字母的另一个端点(传送终点),把传送终点当作下一步入队(并标记已访问/距离)。

注意,这里不把“传送起点格”本身标记为已访问,而是把传送的目标端点标记为访问/距离。

这题题目描述有问题:

我最开始认为传送后就只能移动到普通草地,然后才能再次传送。
不过,题目中的描述是防止在两个 A 间反复横跳。
从一个 A 传送到另一个 A ,然后移动到 B ,这一步也算移动,所以 **可以立即使用 B **

比如下面这个用例:

6 7
#=#####
#ABCDE#
#ABCDE#
#ZXYV.#
#VYXZ@#
#######

走的路线是Z -> A -> 目的地=, 只需要3步

代码如下:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=310;
const int INF = 1e9;
int n, m;
char a[N][N];
int dx[]={-1, 1, 0, 0};
int dy[]={0, 0, 1, -1};
int sx, sy, ex, ey;
// 记录每个大写字母的两个端点
vector<tuple<int,int>> pos[26];
int dista[N][N];//记录距离,同时起到vis[]去重的作用


int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            char c; cin>>c;
            a[i][j]=c;
            if(c=='@') sx=i, sy=j;
            else if(c=='=') ex=i, ey=j;
            else if(isupper(c)){
                pos[c - 'A'].push_back({i, j});
            }
        }

        // 初始化距离
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            dista[i][j] = INF; 
    
    queue<tuple<int, int>> q;
    dista[sx][sy]=0;
    q.push({sx, sy}); 
    while(!q.empty()){
        auto [x, y] = q.front(); q.pop();
        // printf("%c %d %d %d\n", a[x][y], x, y, dista[x][y]);
        if(a[x][y] == '=') 
        {   
            cout<<dista[x][y];
            exit(0);
        }
        for(int i=0;i<4;i++){
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
            if (a[nx][ny] == '#') continue;
   
            //滑梯
            if(isupper(a[nx][ny])){
                int id = a[nx][ny] - 'A';
                // 找到另一个端点
                for (auto [xx, yy] : pos[id]) {
                    if (xx != nx || yy != ny) {
                        if(dista[xx][yy]!=INF) continue;//另一端已访问
                        dista[xx][yy]=dista[x][y]+1;//只需要标记另一端
                        q.push({xx, yy});
                        //  printf("a[nx][ny] %c %d %d %d ——> %d %d %d\n",a[nx][ny], nx, ny, dista[x][y], xx, yy, dista[xx][yy]);
                    }
                }
            } //草地
            else{
                if(dista[nx][ny]!=INF) continue;//已访问
                dista[nx][ny]=dista[x][y]+1;
                q.push({nx, ny});
            }
                
        }
    }

    cout<<-1<<"\n";
    return 0;
}