题目描述

XX 列 YY 行的网格,. 为草地、* 为大石。乳草第 00 周占领格 (Mx,My)(M_x,M_y),此后每周向八连通相邻的草地扩散(保证最终全部被占领),求完全占领所需的星期数。首行输入 X,Y,Mx,MyX,Y,M_x,M_y,随后 YY 行地图;输出一个整数。1≤X,Y≤1001\le X,Y\le100。样例输入 4 3 1 1 / .... ..*. .**.,输出 4。

思路

从起点做八连通 BFS,每个格子被占领的星期数就是它到起点的最短路层数(起点为第 00 周)。石头不入队,答案取所有格子的最大层数。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 15:14
# update_at: 2026-10-01 15:14

from collections import deque

# 八个方向的位移:水平、垂直加上四条对角线
DELTA = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1))


def solve() -> None:
    it = iter(map(int, input().split()))
    x, y, mx, my = next(it), next(it), next(it), next(it)

    # 地图按输入顺序存第 y 行,grid[ny-1] 对应坐标里的第 ny 行
    grid = [input().rstrip() for _ in range(y)]

    # dist 记录每个格子的占领星期数,未访问为 -1;石头永不入队
    dist = [[-1] * x for _ in range(y)]

    def spread(queue: deque) -> None:
        """BFS 一层一层扩散,队头出队的星期数就是该格被占领的最早时间。"""
        while queue:
            ny, nx, week = queue.popleft()
            for dy, dx in DELTA:
                fy, fx = ny + dy, nx + dx
                in_map = 0 <= fy < y and 0 <= fx < x
                if in_map and grid[fy][fx] == "." and dist[fy][fx] == -1:
                    dist[fy][fx] = week + 1
                    queue.append((fy, fx, week + 1))

    dist[my - 1][mx - 1] = 0
    spread(deque([(my - 1, mx - 1, 0)]))

    # 石头的 -1 不影响最大值,答案就是所有格子的最晚占领时间
    print(max(max(row) for row in dist))


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-06 11:40
 * update_at: 2026-10-06 11:40
 */

#include <iostream>
#include <queue>
using namespace std;

typedef long long ll;

const int MAXX = 105;
const int MAXY = 105;

// 八个方向:水平、垂直以及四条对角线
const int DX[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int DY[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

ll X, Y, Mx, My;

char grid[MAXY][MAXX]; // grid[y][x] 存第 y 行第 x 列的字符,'.' 为草地,'*' 为石头
ll dist[MAXY][MAXX];   // dist[y][x] 为格子 (x, y) 被占领的星期数,-1 表示未访问

// 队列节点:格子坐标,对应数组下标
struct Node {
    ll x;
    ll y;
};

queue<Node> q;

int main() {
    cin >> X >> Y >> Mx >> My;
    for (ll y = 1; y <= Y; y++) {
        for (ll x = 1; x <= X; x++) {
            cin >> grid[y][x];
            dist[y][x] = -1;
        }
    }

    // 起点在第 0 周就被占领,从它开始逐层 BFS 扩散
    dist[My][Mx] = 0;
    Node start;
    start.x = Mx;
    start.y = My;
    q.push(start);

    while (!q.empty()) {
        Node now = q.front();
        q.pop();
        for (int d = 0; d < 8; d++) {
            ll nx = now.x + DX[d];
            ll ny = now.y + DY[d];
            if (nx < 1 || nx > X || ny < 1 || ny > Y) {
                continue;
            }
            if (grid[ny][nx] == '*' || dist[ny][nx] != -1) {
                continue;
            }
            dist[ny][nx] = dist[now.y][now.x] + 1;
            Node nxt;
            nxt.x = nx;
            nxt.y = ny;
            q.push(nxt);
        }
    }

    // 答案是最晚被占领格子的星期数,石头的 -1 不影响取最大值
    ll answer = 0;
    for (ll y = 1; y <= Y; y++) {
        for (ll x = 1; x <= X; x++) {
            if (dist[y][x] > answer) {
                answer = dist[y][x];
            }
        }
    }
    cout << answer << endl;
    return 0;
}