#54327: c++解答


tc11421217 (yin)


1. 題目核心

給定一個 $N \times M$ 的地圖,1 代表土地,0 代表海洋。我們需要找出地圖中所有的「連通土地」(上下左右相連),並針對每一塊領土輸出以下資訊:

  1. 最左上角的座標 (最小的 $x$ 與 $y$)。

  2. 最右下角的座標 (最大的 $x$ 與 $y$)。

  3. 面積 (該塊區域中 1 的總數)。

2. 解題策略:淹沒法 (Flood Fill)

我們可以使用 DFS 或 BFS 遍歷整張地圖:

  1. 遍歷地圖:當遇到一個 1 且該點尚未被訪問過,代表發現了一塊新領土。

  2. 開始搜索:從該點出發,搜索所有相連的 1

  3. 更新屬性:在搜索過程中:

    • 紀錄遇到的最小 $x$、最小 $y$、最大 $x$、最大 $y$。

    • 每找到一個 1,面積計數器就 $+1$。

  4. 標記已訪問:將走過的 1 改成 0(或使用 vis 陣列),避免重複計算。

3. C++ 範例程式碼 (使用 DFS)

C++
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int map[505][505];
int R, C;
int minX, minY, maxX, maxY, area;

// 方向陣列:上下左右
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};

void dfs(int x, int y) {
    // 標記為已訪問 (淹沒它)
    map[x][y] = 0;
    area++;
    
    // 更新邊界
    minX = min(minX, x);
    minY = min(minY, y);
    maxX = max(maxX, x);
    maxY = max(maxY, y);

    for (int i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        
        // 檢查邊界與是否為土地
        if (nx >= 0 && nx < R && ny >= 0 && ny < C && map[nx][ny] == 1) {
            dfs(nx, ny);
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    // 題目通常先給 寬(C) 再給 高(R)
    while (cin >> C >> R) {
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                cin >> map[i][j];
            }
        }

        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                if (map[i][j] == 1) {
                    // 初始化領土資訊
                    minX = maxX = i;
                    minY = maxY = j;
                    area = 0;
                    
                    dfs(i, j);
                    
                    // 輸出格式:左上 y x, 右下 y x, 面積
                    // 注意:題目座標可能是 (橫向, 縱向),輸出請依題目要求調整
                    cout << minY << " " << minX << " " << maxY << " " << maxX << " " << area << "\n";
                }
            }
        }
    }
    return 0;
}

4. 常見陷阱

  • 座標順序:題目通常以 $x$ 代表水平方向(行),$y$ 代表垂直方向(列)。在輸出時請務必看清楚是先輸出 $x$ 還是 $y$。

  • 遞迴深度:地圖如果很大(例如 $500 \times 500$ 且全部都是 1),DFS 可能會導致 Stack Overflow。在這種情況下,建議改用 BFS (使用 std::queue) 或是增加系統堆疊大小。

  • 讀取方向:注意 cin >> C >> R 還是 cin >> R >> C