n×m 網格,初始 k 個黑格 (1),其餘白格 (0)。反覆執行:若某白格的上下左右四個方向中,存在「垂直方向有黑格」且「水平方向有黑格」 (即四個角落方向各有一黑),則該白格變黑。直到無新黑格產生。求最終黑格總數。
資料範圍:n,m ≤ 500,k ≤ n·m。最壞全白格需 O(n+m) 輪才穩定,總複雜度 O((n·m)·(n+m)) ≈ 1.25×10⁸,配合簡單陣列操作在 C++ 1s 內通常能過。
cur 存當前狀態,nxt 存下一輪狀態,避免同輪內新黑格影響判斷。cur[i][j]==0 的格子。(up && left) || (up && right) || (down && left) || (down && right)。#include <bits/stdc++.h>
using namespace std;
const int MAXN = 505;
int n, m, k;
bool cur[MAXN][MAXN], nxt[MAXN][MAXN];
inline bool canTurn(int x, int y) {
if (x <= 0 || x >= n-1 || y <= 0 || y >= m-1) return false; // 邊界無法滿足四方向
return (cur[x-1][y] && cur[x][y-1]) ||
(cur[x-1][y] && cur[x][y+1]) ||
(cur[x+1][y] && cur[x][y-1]) ||
(cur[x+1][y] && cur[x][y+1]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T; cin >> T;
for (int cas = 1; cas <= T; ++cas) {
cin >> n >> m >> k;
memset(cur, 0, sizeof(cur));
int initBlack = 0;
for (int i = 0, x, y; i < k; ++i) {
cin >> x >> y;
--x; --y; // 0-based
if (!cur[x][y]) { cur[x][y] = true; ++initBlack; }
}
int added = 0;
while (true) {
memcpy(nxt, cur, sizeof(cur));
int cnt = 0;
for (int i = 1; i < n-1; ++i)
for (int j = 1; j < m-1; ++j)
if (!cur[i][j] && canTurn(i, j)) {
nxt[i][j] = true;
++cnt;
}
if (cnt == 0) break;
added += cnt;
memcpy(cur, nxt, sizeof(cur));
}
cout << "Case #" << cas << ":\n" << initBlack + added << "\n";
}
return 0;
}
觀察規則:黑格像「感染源」向四角擴散。可建立「可被感染」的白格隊列,僅處理受影響區域,類似多源 BFS,可降至 O(n·m) 總複雜度。但本題暴力已足夠,除非時限極嚴。