欢迎光临
我们一直在努力

题解:洛谷 P2873 [USACO07DEC] Mud Puddles S

本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。

欢迎大家订阅我的专栏:算法题解:C++与Python实现!

附上汇总贴:算法竞赛备考冲刺必刷题(C++) | 汇总


【题目来源】

洛谷:P2873 [USACO07DEC] Mud Puddles S – 洛谷

【题目描述】

农夫约翰在早上

6

6

6 点准时离开家去挤奶贝茜。然而,前一天晚上下了大雨,田地里非常泥泞。约翰从坐标平面上的点

(

0

,

0

)

(0,0)

(0,0) 出发,前往位于

(

X

,

Y

)

(X,Y)

(X,Y) 的贝茜(

−

500

≤

X

≤

500

-500\\le X\\le 500

−500≤X≤500;

−

500

≤

Y

≤

500

-500\\le Y\\le 500

−500≤Y≤500)。他可以看到田地上所有

N

(

1

≤

N

≤

10

,

000

)

N(1\\le N\\le 10,000)

N(1≤N≤10,000) 个泥坑,位于点

(

A

i

,

B

i

)

(A_i,B_i)

(Ai​,Bi​)(

−

500

≤

A

i

≤

500

-500\\le A_i\\le 500

−500≤Ai​≤500;

−

500

≤

B

i

≤

500

-500\\le B_i\\le 500

−500≤Bi​≤500)。每个泥坑只占据它所在的点。

刚买了新靴子的农夫约翰绝对不想弄脏他的靴子,但他也想尽快到达贝茜。他已经迟到了,因为他不得不数清所有的泥坑。如果农夫约翰只能平行于坐标轴行走,并且只能在整数坐标点处转弯,那么他到达贝茜并保持靴子干净的最短距离是多少?总会有一条没有泥的路径可以让农夫约翰到达贝茜。

【输入】

  • 第

    1

    1

    1 行:三个用空格分隔的整数:

    X

    ,

    Y

    ,

    N

    X,Y,N

    X,Y,N。

  • 第

    2

    2

    2 行到第

    N

    +

    1

    N+1

    N+1 行:第

    i

    +

    1

    i+1

    i+1 行包含两个用空格分隔的整数:

    A

    i

    A_i

    Ai​ 和

    B

    i

    B_i

    Bi​。

【输出】

  • 第

    1

    1

    1 行:农夫约翰到达贝茜而不踩到泥的最短距离。

【输入样例】

1 2 7
0 2
-1 3
3 1
1 1
4 2
-1 1
2 2

【输出样例】

11

【核心思想】

  • 问题分析:给定起点

    (

    0

    ,

    0

    )

    (0,0)

    (0,0)、终点

    (

    X

    ,

    Y

    )

    (X,Y)

    (X,Y) 和

    N

    N

    N 个泥坑坐标,FJ 只能沿坐标轴方向在整数点移动,不能踩泥坑。求到达终点的最短距离。这是一个BFS最短路/网格避障问题,关键在于将坐标偏移处理(避免负数下标),用BFS在无障碍网格上求最短路。

  • 算法选择:

    • BFS(广度优先搜索):四方向移动,边权均为

      1

      1

      1,BFS天然适合求无权图最短路

    • 坐标偏移:所有坐标加

      500

      500

      500,将

      [

      −

      500

      ,

      500

      ]

      [-500, 500]

      [−500,500] 映射到

      [

      0

      ,

      1000

      ]

      [0, 1000]

      [0,1000],避免负数数组下标

    • 边界剪枝:根据泥坑和起终点的坐标范围,限制BFS搜索边界,避免无限扩展
  • 关键步骤:

    • 读取输入:

      X

      ,

      Y

      ,

      N

      X, Y, N

      X,Y,N 和

      N

      N

      N 个泥坑坐标

      (

      A

      i

      ,

      B

      i

      )

      (A_i, B_i)

      (Ai​,Bi​)

    • 坐标偏移与标记:所有坐标加

      500

      500

      500,泥坑位置

      a

      [

      A

      i

      +

      500

      ]

      [

      B

      i

      +

      500

      ]

      =

      1

      a[A_i+500][B_i+500] = 1

      a[Ai​+500][Bi​+500]=1

    • 确定搜索边界:
      • m

        i

        n

        x

        =

        min

        ⁡

        (

        所有泥坑

        x

        ,

        500

        )

        minx = \\min(\\text{所有泥坑}x, 500)

        minx=min(所有泥坑x,500),

        m

        a

        x

        x

        =

        max

        ⁡

        (

        所有泥坑

        x

        ,

        500

        )

        maxx = \\max(\\text{所有泥坑}x, 500)

        maxx=max(所有泥坑x,500)

      • m

        i

        n

        y

        =

        min

        ⁡

        (

        所有泥坑

        y

        ,

        500

        )

        miny = \\min(\\text{所有泥坑}y, 500)

        miny=min(所有泥坑y,500),

        m

        a

        x

        y

        =

        max

        ⁡

        (

        所有泥坑

        y

        ,

        500

        )

        maxy = \\max(\\text{所有泥坑}y, 500)

        maxy=max(所有泥坑y,500)

      • 搜索范围扩展

        1

        1

        1 格边界:

        [

        m

        i

        n

        x

        −

        1

        ,

        m

        a

        x

        x

        +

        1

        ]

        ×

        [

        m

        i

        n

        y

        −

        1

        ,

        m

        a

        x

        y

        +

        1

        ]

        [minx-1, maxx+1] \\times [miny-1, maxy+1]

        [minx−1,maxx+1]×[miny−1,maxy+1]

    • BFS过程:
      • 起点

        (

        500

        ,

        500

        )

        (500, 500)

        (500,500) 入队,步数

        s

        t

        e

        p

        =

        0

        step = 0

        step=0

      • 取出队首,四方向扩展:
        • 若越界:跳过
        • 若到达终点

          (

          X

          +

          500

          ,

          Y

          +

          500

          )

          (X+500, Y+500)

          (X+500,Y+500):输出

          s

          t

          e

          p

          +

          1

          step + 1

          step+1 并结束

        • 若不是泥坑且未访问:标记访问,入队
    • 输出答案
  • 时间/空间复杂度:

    • 时间复杂度:

      O

      (

      (

      搜索范围宽度

      )

      ×

      (

      搜索范围高度

      )

      )

      O((\\text{搜索范围宽度}) \\times (\\text{搜索范围高度}))

      O((搜索范围宽度)×(搜索范围高度)),最坏

      O

      (

      1002

      ×

      1002

      )

      O(1002 \\times 1002)

      O(1002×1002)

    • 空间复杂度:

      O

      (

      1005

      ×

      1005

      )

      O(1005 \\times 1005)

      O(1005×1005),访问标记和泥坑标记数组

  • BFS网格最短路的核忈思想:

    • 坐标偏移处理负数:通过统一加偏移量,将可能为负的坐标映射到非负数组下标
    • 层序扩展保证最优:BFS按步数分层,首次到达终点时即为最短路径(曼哈顿距离意义下)
    • 边界限制优化:根据输入数据的实际范围确定搜索边界,避免向无穷远处扩展
    • 适用于"网格避障最短路径"类问题,核心是正确处理坐标和边界
  • 【解题思路】

    【算法标签】

    #普及- #BFS-二维

    【代码详解】

    #include <bits/stdc++.h>
    using namespace std;
    int n, sx, sy, minx=1e9, miny=1e9, maxx=–1e9, maxy=–1e9, dx[4]={–1,1,0,0}, dy[4]={0,0,–1,1}, tx, ty, tstep;
    int a[1005][1005]={0}, vis[1005][1005]={0};
    struct node {
    int x, y, step, visit;
    };
    int main()
    {
    cin >> sx >> sy >> n; // 输入结束坐标及n
    for (int i=1; i<=n; i++) { // 遍历n个泥塘坐标
    int tmp1, tmp2;
    cin >> tmp1 >> tmp2; // 输入坐标
    minx = min(minx, tmp1+500); // 计算x坐标最小值
    maxx = max(maxx, tmp1+500); // 计算x坐标最大值
    miny = min(miny, tmp2+500); // 计算y坐标最小值
    maxy = max(maxy, tmp2+500); // 计算y坐标最大值
    a[tmp1+500][tmp2+500]=1; // 因为存在负数,x和y均加上500,对于泥塘的坐标,a数组置为1
    }
    minx = min(minx, 500); // 再与(0,0)(即(500,500))进行比较
    maxx = max(maxx, 500);
    miny = min(miny, 500);
    maxy = max(maxy, 500);
    queue<node> q; // 定义队列
    node tp = {500, 500, 0}; // 队头数据
    q.push(tp); // 压入队列
    while (!q.empty()) { // bfs模板
    tp = q.front();
    q.pop();
    for (int i=0; i<4; i++) { // 进行上下左右位置移动
    tx = tp.x + dx[i];
    ty = tp.y + dy[i];
    tstep = tp.step+1; // 每移动一个格子,step加1
    if (tx<minx–1||tx>maxx+1||ty<miny–1||ty>maxy+1) continue; // 当移动后的坐标越界时,继续循环
    if (tx==sx+500 && ty==sy+500) { // 当遇到终点时,打印step,退出循环
    cout << tstep << endl;
    return 0;
    }
    if (a[tx][ty]==0 && vis[tx][ty]==0) { // 将要移动的坐标不是泥塘,且没有访问过
    vis[tx][ty]=1; // 更新vis数组
    node t = {tx, ty, tstep}; // 初始化t节点
    q.push(t); // 将其压入队列中
    }
    }
    }

    return 0;
    }

    【运行结果】

    1 2 7
    0 2
    -1 3
    3 1
    1 1
    4 2
    -1 1
    2 2
    11

    赞(0)
    未经允许不得转载:171主机测评 » 题解:洛谷 P2873 [USACO07DEC] Mud Puddles S
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址