C++ / ACM 自学笔记 · v5.0

P1141 01 迷宫

原题入口

对应章节:五、数据结构与算法 → (十二) 搜索:递归、回溯、DFS、BFS 与记忆化。

(一) 任务与输出目标

邻格数字不同才能移动,回答每个起点能到达多少格。

(二) 建模与推导

数字不同的相邻格子之间可以双向移动,所以能到达的格子构成连通块。同一块内所有起点的答案相同,不必每次询问重新 BFS。预处理块编号 id 和块大小 size;搜索时仅沿数字不同的边扩展,询问时直接读 size[id[x][y]]。

(三) 手算与过程

棋盘 01/10 的四格都通过不同数字的邻边连通,任何格子的答案都为 4。

按具体数据展开的处理与返回过程

(四) 带注释实现

完整源文件

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

void solve() {
    int n, qn;
    cin >> n >> qn;
    vector<string> a(n);
    for (auto& row : a)
        cin >> row;
    vector<vector<int>> id(n, vector<int>(n, -1));
    vector<int> sizes;
    int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            if (id[i][j] != -1)
                continue;
            int block = sizes.size(), count = 0;
            queue<pair<int, int>> q;
            q.emplace(i, j);
            id[i][j] = block;
            while (!q.empty()) {
                auto [x, y] = q.front();
                q.pop();
                ++count;
                for (int d = 0; d < 4; ++d) {
                    int u = x + dx[d], v = y + dy[d];
                    if (u >= 0 && u < n && v >= 0 && v < n && id[u][v] == -1 &&
                        a[u][v] != a[x][y]) {
                        id[u][v] = block;
                        q.emplace(u, v); // 沿不同数字的边归入同一块。
                    }
                }
            }
            sizes.push_back(count);
        }
    while (qn--) {
        int x, y;
        cin >> x >> y;
        cout << sizes[id[x - 1][y - 1]] << '\n';
    }
}

signed main() {
    ios::sync_with_stdio(false); // 关闭同步,使用 cin 与 cout 完成输入输出。
    cin.tie(0), cout.tie(0);

    int T = 1; // 本题读入一组数据。
    // cin >> T; // 题目给出测试组数时开启,并在 solve 中处理一组。
    while (T--)
        solve();
}

(五) 复杂度

预处理 \(O(n^2)\),q 次询问 \(O(q)\),空间 \(O(n^2)\)。

返回本章题解索引 · 返回全部题号索引

查阅笔记正文与全部题解 · Ctrl / ⌘ K