超级详细题解:矩阵中的连通区域标记(BF
2025-07-06 11:56:54
发布于:广东
- 题目描述
 给定一个 n × n 的矩阵,其中:
0 表示可以通行的区域
1 表示障碍物(不可通行)
目标:
所有与矩阵边界相连的 0 保持 0。
所有被 1 完全包围的 0 改为 2。
1 保持不变。
示例输入:
text
5
1 1 1 1 1
1 0 0 0 1
1 0 1 0 1
1 0 0 0 1
1 1 1 1 1
示例输出:
text
1 1 1 1 1
1 0 0 0 1
1 0 1 0 1
1 0 0 0 1
1 1 1 1 1
2. 解题思路
核心思想
从边界出发,用 BFS/DFS 标记所有可达的 0:
如果 0 能通过上下左右移动到达边界,则它属于“边界连通区域”,保持 0。
如果 0 被 1 完全包围,无法到达边界,则改为 2。
算法选择
BFS(广度优先搜索):
使用队列逐层遍历,适合较大的矩阵(避免递归栈溢出)。
DFS(深度优先搜索):
递归实现更简洁,但可能栈溢出(适用于小矩阵)。
步骤
输入矩阵。
遍历所有边界点:
如果 vis[i][j] == 0,则进行 BFS/DFS 标记所有可达的 0 为 2。
输出矩阵:
1 保持 1(障碍物)。
2 表示原本是 0 但被 BFS/DFS 访问过(边界连通区域)。
0 表示未被访问的 0(被 1 包围的区域)。
- 代码实现(BFS版本)
 cpp
 #include <bits/stdc++.h>
 using namespace std;
int vis[35][35];  // 矩阵
int dx[] = {1, -1, 0, 0};  // 方向数组:下、上、右、左
int dy[] = {0, 0, 1, -1};
int n;
struct node {
int x, y;  // 坐标
};
void bfs(int x1, int y1) {
queue<node> q;
q.push({x1, y1});
vis[x1][y1] = 2;  // 标记为边界连通区域
while (!q.empty()) {
    node u = q.front();
    q.pop();  // 弹出队首
    
    // 检查四个方向
    for (int i = 0; i < 4; i++) {
        int nx = u.x + dx[i];
        int ny = u.y + dy[i];
        // 检查是否越界,并且是否是未访问的 0
        if (nx >= 1 && nx <= n && ny >= 1 && ny <= n && vis[nx][ny] == 0) {
            vis[nx][ny] = 2;  // 标记为已访问
            q.push({nx, ny});  // 加入队列
        }
    }
}
}
int main() {
cin >> n;
// 输入矩阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> vis[i][j];
}
}
// 遍历边界,进行 BFS
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
        if ((i == 1 || i == n || j == 1 || j == n) && vis[i][j] == 0) {
            bfs(i, j);
        }
    }
}
// 输出结果
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
        if (vis[i][j] == 2) {
            cout << 0 << " ";  // 边界连通区域
        } else if (vis[i][j] == 1) {
            cout << 1 << " ";  // 障碍物
        } else if (vis[i][j] == 0) {
            cout << 2 << " ";  // 被包围的 0
        }
    }
    cout << endl;
}
return 0;
}
4. 代码实现(DFS版本)
cpp
#include <bits/stdc++.h>
using namespace std;
int vis[35][35];
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
int n;
void dfs(int x, int y) {
if (x < 1 || x > n || y < 1 || y > n || vis[x][y] != 0) return;
vis[x][y] = 2;  // 标记为边界连通区域
for (int i = 0; i < 4; i++) {
dfs(x + dx[i], y + dy[i]);  // 递归搜索四个方向
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> vis[i][j];
}
}
// 遍历边界,进行 DFS
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
        if ((i == 1 || i == n || j == 1 || j == n) && vis[i][j] == 0) {
            dfs(i, j);
        }
    }
}
// 输出结果
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
        if (vis[i][j] == 2) {
            cout << 0 << " ";
        } else if (vis[i][j] == 1) {
            cout << 1 << " ";
        } else if (vis[i][j] == 0) {
            cout << 2 << " ";
        }
    }
    cout << endl;
}
return 0;
}
5. 复杂度分析
算法	时间复杂度	空间复杂度
BFS	O(n²)	O(n²)
DFS	O(n²)	O(n²)(递归栈可能溢出)
BFS 更适合大矩阵(队列实现,无栈溢出风险)。
DFS 代码更简洁(递归实现,适合小矩阵)。
- 实际应用
 图像处理:标记连通区域(如 Photoshop 的魔棒工具)。
游戏地图生成:判断封闭区域(如迷宫的可达性分析)。
自动化测试:检测 UI 元素的封闭性。
- 总结
 BFS/DFS 是解决连通性问题的经典方法。
从边界出发,标记所有可达的 0。
注意 = 和 == 的区别(常见错误)。
BFS 用队列,DFS 用递归/栈,选择适合的算法。
这里空空如也






有帮助,赞一个