题解:洛谷 P2958 Papaya Jungle

【题目来源】

洛谷:P2958 [USACO09OCT] Papaya Jungle G - 洛谷

【题目描述】

Bessie 不小心游荡出 Farmer John 的田地,而走进了相邻的农民的地里。她举起一个木瓜,木瓜对奶牛来说可是不可多得的美味。这个木瓜林像一般的威斯康星州的田地一样被分割成一个 \(R\)\(C\) 列的网格 \((1 \le R,C \le 40)\)。Bessie 可以从一个格沿着一条跟 X 轴或 Y 轴平行的直线走到邻接的另一个格。Bessie 发现一开始她自己在木瓜林的 \((1,1)\),也就是第一行第一列慢悠悠地咀嚼着木瓜。

Bessie 总是用她最信赖地双筒望远镜去数每一个邻接的格里挂着的木瓜的数目。然后她就游荡到那个有最多没有被吃掉的木瓜的邻接的格子(保证这样的格子只有一个)。

按照这种移动方法,最终 Bessie 总是会在 \((R,C)\) 停止然后吃掉那里的木瓜。

给定这个木瓜林的大小及每个格的木瓜数 \(F_{ij}(1 \le F_{ij} \le 100)\),求 Bessie 一共吃了多少个木瓜。

【输入】

第一行:两个用空格分割的整数 \(R\)\(C\)

接下来 \(R\) 行:第 \(i+1\) 行用 \(C\) 个用空格分隔的整数描述丛林的第 \(i\)\(F_{i1},F_{i2},\dots,F_{iC}\)

【输出】

第一行:一个整数,表示 Bessie 在坐标 \((R,C)\) 的右下角谷仓吃完木瓜时吃的木瓜总数。

【输入样例】

3 4
3 3 4 5
4 5 3 2
1 7 4 2

【输出样例】

39

【核心思想】

  1. 问题分析:给定 \(R \times C\) 的木瓜林,Bessie 从 \((1,1)\) 出发,每次移动到四邻域中木瓜数最多且未被吃过的格子(保证唯一),直到到达 \((R,C)\)。求吃掉的木瓜总数。这是一个贪心模拟/BFS变体问题,关键在于每次只选择最优邻域移动,路径唯一确定,无需搜索所有可能。

  2. 算法选择

    • 贪心模拟:从 \((1,1)\) 开始,每步在四邻域中选择木瓜数最多且未访问的格子移动,累加木瓜数,直到到达 \((R,C)\)
    • 访问标记\(vis[i][j]\) 记录格子是否已被吃过,避免重复访问
  3. 关键步骤

    • 读取输入\(R, C\) 和木瓜数量矩阵 \(a[1..R][1..C]\)
    • 初始化\(sum = a[1][1]\)\(vis[1][1] = 1\),起点 \((1,1)\) 入队
    • 贪心移动(循环直到到达 \((R,C)\)):
      • 取出当前位置 \((x, y)\)
      • 遍历四邻域,寻找未访问且木瓜数最多的格子 \((xt, yt)\)
        • \(maxn = -1\),遍历四方向 \((nx, ny)\)
          • 若越界或已访问:跳过
          • \(a[nx][ny] > maxn\):更新 \(maxn\)\((xt, yt)\)
      • \(sum \mathrel{+}= a[xt][yt]\),标记 \(vis[xt][yt] = 1\)
      • \((xt, yt) = (R, C)\):结束循环
      • 否则:\((xt, yt)\) 入队继续
    • 输出 \(sum\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(R \cdot C)\),每步检查 \(4\) 个邻域,最多走 \(R \cdot C\)
    • 空间复杂度:\(O(R \cdot C)\),访问标记和队列
  5. 贪心模拟的核心思想

    • 局部最优即全局最优:题目保证每步最优邻域唯一,且路径必然到达 \((R,C)\),因此贪心选择即可确定唯一路径
    • 访问标记防重复:木瓜被吃后不再存在,\(vis\) 数组确保不会回到已访问格子
    • 擂台法选最大:每步在四邻域中打擂台选出最大值,\(O(4) = O(1)\)
    • 适用于"确定性贪心路径 + 网格移动"类问题,核心是模拟每一步的最优选择

【解题思路】

【算法标签】

普及- #BFS-二维

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int r, c, a[45][45], vis[45][45], sum=0;
int dx[4]={-1,1,0,0}, dy[4]={0,0,-1,1};
struct node {
    int x, y;
};
int main()
{
    cin >> r >> c;  // 输入r和c
    for (int i=1; i<=r; i++) {  // 遍历r行和c列,输入每个格子的木瓜数量
        for (int j=1; j<=c; j++) {
            cin >> a[i][j];
        }
    }
    queue<node> q;  // 定义队列
    node tp = {1, 1};  // 将左上角压入队列中
    q.push(tp);
    vis[1][1]=1;  // 修改当前格子vis为1
    sum += a[1][1];  // 将该格子的木瓜数量加起来
    while (!q.empty()) {  // BFS模板
        tp = q.front();
        q.pop();
        int xx, yy, xt, yt, maxn=-1e9;
        for (int i=0; i<4; i++) {  // 上下左右分别遍历
            xx = tp.x+dx[i], yy = tp.y+dy[i];
            if (xx<1||xx>r||yy<1||yy>c||vis[xx][yy]==1||a[xx][yy]==0) continue;  // 如果坐标越界或vis为1或该格子数量为0,则继续循环
            if (a[xx][yy]>maxn) {  // 使用擂台法找到四个方向中最多的没被吃掉的木瓜数,并记录其坐标
                maxn = a[xx][yy];
                xt = xx;
                yt = yy;
            }
        }
        sum += a[xt][yt];  // 确认下一次移动的格子后,将下一个格子的木瓜数加到sum中
        if (xt==r && yt==c) break;  // 当移动到(r,c),退出循环
        node t = {xt, yt};  // 将下一个格子压入队列中
        q.push(t);
        vis[xt][yt] = 1;  // 并将下一个格子的vis修改为1
    }
    cout << sum << endl;  // 输出sum
    return 0;
}

【运行结果】

3 4
3 3 4 5
4 5 3 2
1 7 4 2
39
posted @ 2026-08-28 15:56  团爸讲算法  阅读(4)  评论(0)    收藏  举报