题目描述

在一个 10×1010 \times 10 的二维数组中,* 围成若干闭合曲线。统计 * 围成的闭合曲线中水平线和垂直线交点的数目,即为图形的面积。例如样例中 * 围住了 15 个点,面积为 15。

输入为 10 行,每行 10 个用空格分隔的 0/1 整数,1 表示 *;输出面积(一个整数)。样例输入(前 5 行为 0 0 0 0 0 0 0 0 0 0、0 0 0 0 1 1 1 0 0 0、0 0 0 0 1 0 0 1 0 0、0 0 0 0 0 1 0 0 1 0、0 0 1 0 0 0 1 0 1 0,后 5 行为 0 1 0 1 0 1 0 0 1 0、0 1 0 0 1 1 0 1 1 0、0 0 1 0 0 0 0 1 0 0、0 0 0 1 1 1 1 1 0 0、0 0 0 0 0 0 0 0 0 0),样例输出为:

text
15

思路

“被 * 围住"等价于"该 0 格与网格边界不连通”。反过来做:从最外圈的所有 0 格出发做一次多源 BFS 洪水填充,只穿过 0 格,能走到的都是外部格;剩下未被染色的 0 格就是被围住的内部点,其个数即面积。曲线是否有缺口无需单独判断——有缺口时洪水会漏进去,内部点自动被染成外部。

参考代码

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-09-30 07:02
# update_at: 2026-09-30 07:02

import sys
from collections import deque
from collections.abc import Iterator

SIZE = 10  # 题面固定 10×10


def neighbors(cell: tuple[int, int]) -> Iterator[tuple[int, int]]:
    """产出上下左右四个相邻格(可能越界,由调用点判边界)。"""
    r, c = cell
    yield r - 1, c
    yield r + 1, c
    yield r, c - 1
    yield r, c + 1


def solve() -> None:
    # 按行优先读扁平 token:真实数据里有测例只给了 9 行,缺的行自然补 0(仍是 0,不影响答案)。
    grid = [[0] * SIZE for _ in range(SIZE)]
    for i, value in enumerate(map(int, sys.stdin.buffer.read().split())):
        grid[i // SIZE][i % SIZE] = value  # i 超过 100 的部分被丢弃

    outside = [[False] * SIZE for _ in range(SIZE)]
    queue: deque[tuple[int, int]] = deque()

    # 边界上的 0 都是外部:从它们洪水填充,能走到的 0 全部属于图形外。
    for r, c in [
        (r, c)
        for r in range(SIZE)
        for c in range(SIZE)
        if grid[r][c] == 0 and (r in (0, SIZE - 1) or c in (0, SIZE - 1))
    ]:
        if not outside[r][c]:
            outside[r][c] = True
            queue.append((r, c))

    while queue:
        r, c = queue.popleft()
        for nr, nc in neighbors((r, c)):
            in_board = 0 <= nr < SIZE and 0 <= nc < SIZE
            if in_board and grid[nr][nc] == 0 and not outside[nr][nc]:
                outside[nr][nc] = True
                queue.append((nr, nc))

    # 剩下没被外部染色到的 0,就是被 * 围住的内部点,个数即面积。
    print(sum(grid[r][c] == 0 and not outside[r][c] for r in range(SIZE) for c in range(SIZE)))


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-05 12:00
 * update_at: 2026-10-05 12:01
 */
#include <cstdio>

typedef long long ll;

const int N = 10; // 题面固定 10×10 的网格

int grid[N][N];   // grid[r][c]:1 表示 *(墙),0 表示待判定的点
bool outside[N][N]; // outside[r][c]:该 0 格是否已被判定为外部

// 多源 BFS 洪水填充:从边界上的所有 0 格出发,把能走到的 0 格全部染成外部。
// 只穿过 0 格,遇到 1(墙)就停;曲线有缺口时洪水会漏进去,缺口自动被识别。
void bfs_fill() {
    int qx[N * N], qy[N * N]; // 队列存格子坐标,队列含义:待扩散的外部格
    int head = 0, tail = 0;

    // 种子:最外圈上的 0 格一定属于外部,全部入队
    for (int r = 0; r < N; r++)
        for (int c = 0; c < N; c++)
            if (grid[r][c] == 0 && (r == 0 || r == N - 1 || c == 0 || c == N - 1)) {
                outside[r][c] = true;
                qx[tail] = r;
                qy[tail] = c;
                tail++;
            }

    while (head < tail) {
        int r = qx[head], c = qy[head];
        head++;
        int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 四方向相邻
        for (int k = 0; k < 4; k++) {
            int nr = r + dir[k][0], nc = c + dir[k][1];
            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue; // 越界
            if (grid[nr][nc] == 0 && !outside[nr][nc]) {
                outside[nr][nc] = true;
                qx[tail] = nr;
                qy[tail] = nc;
                tail++;
            }
        }
    }
}

int main() {
    // 按行优先读扁平整数:真实数据里有测例只有 9 行,缺的位置保持 0,不影响答案
    for (int i = 0; i < N * N; i++)
        scanf("%d", &grid[i / N][i % N]);

    bfs_fill();

    // 剩下没被染成外部的 0 格,就是被 * 围住的内部点,个数即面积
    int ans = 0;
    for (int r = 0; r < N; r++)
        for (int c = 0; c < N; c++)
            if (grid[r][c] == 0 && !outside[r][c])
                ans++;

    printf("%d\n", ans);
    return 0;
}