// DFS遍历 voiddfs(int u){ st[u] = true; // 标记已访问 cout << u << " "; // 输出当前节点 // 遍历所有相邻节点 for (int v : g[u]) { if (!st[v]) { // 如果未访问过 dfs(v); // 递归访问 } } }
intmain(){ int n, m; // n个节点,m条边 cin >> n >> m; // 读入边 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; g[a].push_back(b); // 无向图,双向连边 g[b].push_back(a); } // 从节点1开始DFS遍历 dfs(1); return0; }
// DFS遍历连通块 voiddfs(int u){ st[u] = true; // 标记已访问 // 遍历相邻节点 for (int v : g[u]) { if (!st[v]) { dfs(v); } } }
intmain(){ int n, m; cin >> n >> m; // 读入边 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; g[a].push_back(b); g[b].push_back(a); } int cnt = 0; // 连通块数量 // 遍历所有节点 for (int i = 1; i <= n; i++) { if (!st[i]) { // 如果节点未访问 dfs(i); // DFS遍历该连通块 cnt++; // 连通块数量+1 } } cout << "连通块数量:" << cnt << endl; return0; }
constint N = 105; int n, m; int g[N][N]; // 存储迷宫 bool st[N][N]; // 标记数组
// 方向数组 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
// DFS搜索路径 booldfs(int x, int y){ // 到达终点 if (x == n - 1 && y == m - 1) { returntrue; } // 标记当前格子已访问 st[x][y] = true; // 遍历四个方向 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 判断边界 if (nx < 0 || nx >= n || ny < 0 || ny >= m) { continue; } // 判断是否可以走(不是障碍物且未访问) if (g[nx][ny] == 0 && !st[nx][ny]) { if (dfs(nx, ny)) { // 如果从(nx,ny)能到达终点 returntrue; } } } returnfalse; // 所有方向都走不通 }
intmain(){ cin >> n >> m; // 读入迷宫 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> g[i][j]; } } // 从起点开始DFS if (dfs(0, 0)) { cout << "Yes" << endl; } else { cout << "No" << endl; } return0; }
constint N = 100; vector<int> g[N]; // 邻接表 int dist[N]; // 距离数组,dist[i]表示从起点到节点i的最短距离
voidbfs(int start){ queue<int> q; q.push(start); dist[start] = 0; // 起点距离为0 while (!q.empty()) { int u = q.front(); q.pop(); // 遍历相邻节点 for (int v : g[u]) { if (dist[v] == -1) { // 如果未访问过(初始化为-1) dist[v] = dist[u] + 1; // 距离 = 当前距离 + 1 q.push(v); // 加入队列 } } } }
intmain(){ int n, m; cin >> n >> m; // 初始化距离数组为-1(表示未访问) for (int i = 1; i <= n; i++) { dist[i] = -1; } // 读入边 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; g[a].push_back(b); g[b].push_back(a); } // 从节点1开始BFS bfs(1); // 输出从节点1到所有节点的最短距离 for (int i = 1; i <= n; i++) { cout << "从节点1到节点" << i << "的最短距离:" << dist[i] << endl; } return0; }
voidbfs(int start){ queue<int> q; q.push(start); st[start] = true; while (!q.empty()) { int u = q.front(); q.pop(); cout << u << " "; // 输出当前节点 // 遍历相邻节点 for (int v : g[u]) { if (!st[v]) { st[v] = true; q.push(v); } } } cout << endl; }
intmain(){ int n, m; cin >> n >> m; // 读入边 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; g[a].push_back(b); g[b].push_back(a); } // 从节点1开始BFS bfs(1); return0; }
constint N = 100005; vector<int> g[N]; int dist[N]; // 距离数组
voidbfs(int start){ queue<int> q; q.push(start); dist[start] = 0; while (!q.empty()) { int u = q.front(); q.pop(); // 如果到达目标节点,可以提前退出(可选) // if (u == target) break; // 遍历相邻节点 for (int v : g[u]) { if (dist[v] == -1) { // 未访问过 dist[v] = dist[u] + 1; // 更新距离 q.push(v); } } } }
intmain(){ int n, m; cin >> n >> m; // 初始化距离数组 for (int i = 1; i <= n; i++) { dist[i] = -1; } // 读入边 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; g[a].push_back(b); g[b].push_back(a); } // 从节点1开始BFS bfs(1); // 输出从节点1到节点n的最短距离 if (dist[n] == -1) { cout << -1 << endl; // 不可达 } else { cout << dist[n] << endl; } return0; }
constint N = 105; int n, m; int g[N][N]; // 存储迷宫 int dist[N][N]; // 距离数组
// 方向数组 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
intbfs(int sx, int sy, int ex, int ey){ queue<pair<int, int>> q; q.push({sx, sy}); dist[sx][sy] = 0; while (!q.empty()) { int x = q.front().first; int y = q.front().second; q.pop(); // 到达终点 if (x == ex && y == ey) { return dist[x][y]; } // 遍历四个方向 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 判断边界 if (nx < 0 || nx >= n || ny < 0 || ny >= m) { continue; } // 判断是否可以走(不是障碍物且未访问) if (g[nx][ny] == 0 && dist[nx][ny] == -1) { dist[nx][ny] = dist[x][y] + 1; q.push({nx, ny}); } } } return-1; // 不可达 }
intmain(){ cin >> n >> m; // 初始化距离数组 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { dist[i][j] = -1; } } // 读入迷宫 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> g[i][j]; } } // BFS搜索最短路径 int result = bfs(0, 0, n - 1, m - 1); if (result == -1) { cout << "不可达" << endl; } else { cout << "最短路径长度:" << result << endl; } return0; }
constint N = 105; int n, m; char g[N][N]; // 存储网格 bool st[N][N]; // 标记数组
// 方向数组 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
// BFS标记整个岛屿 voidbfs(int sx, int sy){ queue<pair<int, int>> q; q.push({sx, sy}); st[sx][sy] = true; while (!q.empty()) { int x = q.front().first; int y = q.front().second; q.pop(); // 遍历四个方向 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 判断边界 if (nx < 0 || nx >= n || ny < 0 || ny >= m) { continue; } // 如果是陆地且未访问 if (g[nx][ny] == '1' && !st[nx][ny]) { st[nx][ny] = true; q.push({nx, ny}); } } } }
intmain(){ cin >> n >> m; // 读入网格 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> g[i][j]; } } int cnt = 0; // 岛屿数量 // 遍历所有位置 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { // 如果遇到陆地且未访问 if (g[i][j] == '1' && !st[i][j]) { bfs(i, j); // BFS标记整个岛屿 cnt++; // 岛屿数量+1 } } } cout << "岛屿数量:" << cnt << endl; return0; }
输入示例:
1 2 3 4 5
4 5 11110 11010 11000 00000
输出示例:
1
岛屿数量:1
网格图示:
1 2 3 4
11110 11010 11000 00000
所有连通的’1’构成一个岛屿
输入示例2:
1 2 3 4 5
4 5 11000 11000 00100 00011
输出示例2:
1
岛屿数量:3
解释: 有三个独立的岛屿。
BFS常见错误
错误1:忘记初始化距离数组
1 2 3 4 5 6 7 8 9
// ❌ 错误写法 int dist[N]; // 忘记初始化,dist数组可能包含随机值
// ✅ 正确写法 int dist[N]; for (int i = 0; i < N; i++) { dist[i] = -1; // 初始化为-1表示未访问 }
constint N = 105; int n, m; char g[N][N]; // 存储网格 bool st[N][N]; // 标记数组
// 方向数组:上、右、下、左 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
// DFS洪泛填充 voidfloodFill(int x, int y, char oldColor, char newColor){ // 边界判断 if (x < 0 || x >= n || y < 0 || y >= m) { return; } // 如果当前格子不是目标颜色或已访问,返回 if (g[x][y] != oldColor || st[x][y]) { return; } // 填充新颜色并标记 g[x][y] = newColor; st[x][y] = true; // 递归填充四个方向 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; floodFill(nx, ny, oldColor, newColor); } }
intmain(){ cin >> n >> m; // 读入网格 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> g[i][j]; } } int sx, sy; // 起始坐标 char newColor; // 新颜色 cin >> sx >> sy >> newColor; char oldColor = g[sx][sy]; // 原颜色 // 如果新颜色和原颜色相同,不需要填充 if (oldColor != newColor) { floodFill(sx, sy, oldColor, newColor); } // 输出填充后的网格 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cout << g[i][j]; } cout << endl; } return0; }
constint N = 105; int n, m; vector<vector<char>> image; // 存储图像 bool st[N][N]; // 标记数组
// 方向数组 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
voidfloodFill(int x, int y, char oldColor, char newColor){ // 边界判断 if (x < 0 || x >= n || y < 0 || y >= m) { return; } // 如果当前格子不是目标颜色或已访问,返回 if (image[x][y] != oldColor || st[x][y]) { return; } // 填充新颜色并标记 image[x][y] = newColor; st[x][y] = true; // 递归填充四个方向 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; floodFill(nx, ny, oldColor, newColor); } }
intmain(){ cin >> n >> m; // 读入图像 image.resize(n, vector<char>(m)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> image[i][j]; } } int sx, sy; char newColor; cin >> sx >> sy >> newColor; char oldColor = image[sx][sy]; // 如果新颜色和原颜色相同,不需要填充 if (oldColor != newColor) { floodFill(sx, sy, oldColor, newColor); } // 输出填充后的图像 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cout << image[i][j]; } cout << endl; } return0; }
constint N = 105; int n, m; char g[N][N]; // 存储网格 int label[N][N]; // 标记数组,label[i][j]表示(i,j)所属的区域编号 bool st[N][N]; // 访问标记
// 方向数组 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
// BFS标记连通区域 voidbfs(int sx, int sy, int regionId){ queue<pair<int, int>> q; q.push({sx, sy}); label[sx][sy] = regionId; st[sx][sy] = true; while (!q.empty()) { int x = q.front().first; int y = q.front().second; q.pop(); // 遍历四个方向 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 边界判断 if (nx < 0 || nx >= n || ny < 0 || ny >= m) { continue; } // 如果是相同类型的格子且未标记 if (g[nx][ny] == g[sx][sy] && !st[nx][ny]) { label[nx][ny] = regionId; // 标记为同一区域 st[nx][ny] = true; q.push({nx, ny}); } } } }
intmain(){ cin >> n >> m; // 读入网格 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> g[i][j]; } } int regionId = 0; // 区域编号从0开始 // 遍历所有格子 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { // 如果遇到未标记的格子 if (!st[i][j]) { bfs(i, j, regionId); // 标记整个连通区域 regionId++; // 区域编号+1 } } } cout << "连通区域数量:" << regionId << endl; // 输出每个格子的区域编号 cout << "区域标记:" << endl; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cout << label[i][j] << " "; } cout << endl; } return0; }
constint N = 105; int n, m; char g[N][N]; bool st[N][N];
// 方向数组 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
// 计算单个岛屿的周长 intcalculatePerimeter(int sx, int sy){ queue<pair<int, int>> q; q.push({sx, sy}); st[sx][sy] = true; int perimeter = 0; while (!q.empty()) { int x = q.front().first; int y = q.front().second; q.pop(); // 检查四个方向,计算周长贡献 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 如果相邻格子是边界或水,贡献1的周长 if (nx < 0 || nx >= n || ny < 0 || ny >= m || g[nx][ny] == '0') { perimeter++; } elseif (!st[nx][ny]) { // 如果是未访问的陆地,加入队列 st[nx][ny] = true; q.push({nx, ny}); } } } return perimeter; }
intmain(){ cin >> n >> m; // 读入网格 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> g[i][j]; } } int totalPerimeter = 0; // 遍历所有格子 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { // 如果遇到陆地且未访问 if (g[i][j] == '1' && !st[i][j]) { // 使用洪泛算法标记整个岛屿并计算周长 totalPerimeter += calculatePerimeter(i, j); } } } cout << "总周长:" << totalPerimeter << endl; return0; }
constint N = 105; int n, m; char g[N][N]; bool st[N][N];
// 方向数组 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1};
// 标记连通区域(用于标记边界岛屿) voidmarkRegion(int sx, int sy, bool isBoundary){ queue<pair<int, int>> q; q.push({sx, sy}); st[sx][sy] = true; while (!q.empty()) { int x = q.front().first; int y = q.front().second; q.pop(); // 遍历四个方向 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 边界判断 if (nx < 0 || nx >= n || ny < 0 || ny >= m) { continue; } // 如果是陆地且未访问 if (g[nx][ny] == '0' && !st[nx][ny]) { st[nx][ny] = true; q.push({nx, ny}); } } } }
intmain(){ cin >> n >> m; // 读入网格 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> g[i][j]; } } // 第一步:标记所有边界上的岛屿(这些不是封闭岛屿) // 标记上边界和下边界 for (int j = 0; j < m; j++) { if (g[0][j] == '0' && !st[0][j]) { markRegion(0, j, true); } if (g[n-1][j] == '0' && !st[n-1][j]) { markRegion(n-1, j, true); } } // 标记左边界和右边界 for (int i = 0; i < n; i++) { if (g[i][0] == '0' && !st[i][0]) { markRegion(i, 0, true); } if (g[i][m-1] == '0' && !st[i][m-1]) { markRegion(i, m-1, true); } } // 第二步:统计封闭岛屿数量(内部未被标记的陆地) int cnt = 0; // 遍历内部格子(不包括边界) for (int i = 1; i < n - 1; i++) { for (int j = 1; j < m - 1; j++) { // 如果遇到陆地且未访问(说明是封闭岛屿) if (g[i][j] == '0' && !st[i][j]) { markRegion(i, j, false); // 标记整个封闭岛屿 cnt++; // 封闭岛屿数量+1 } } } cout << "封闭岛屿数量:" << cnt << endl; return0; }
输入示例:
1 2 3 4 5 6
5 8 11111111 10000111 11000011 11100111 11111111
输出示例:
1
封闭岛屿数量:1
网格图示:
1 2 3 4 5
11111111 10000111 11000011 11100111 11111111
边界上的陆地已经被标记
内部的连通区域构成1个封闭岛屿
洪泛算法常见错误
错误1:忘记检查新颜色和原颜色是否相同
1 2 3 4 5 6 7 8 9 10 11 12 13
// ❌ 错误写法 voidfloodFill(int x, int y, char oldColor, char newColor){ // 如果新颜色和原颜色相同,会导致无限递归或循环 if (g[x][y] != oldColor) return; g[x][y] = newColor; // 如果newColor == oldColor,永远满足条件 // ... }
// ✅ 正确写法 voidfloodFill(int x, int y, char oldColor, char newColor){ if (oldColor == newColor) return; // 提前判断 // ... }
错误2:边界判断位置错误
1 2 3 4 5 6 7 8 9 10 11 12 13
// ❌ 错误写法 voidfloodFill(int x, int y, char oldColor, char newColor){ if (g[x][y] != oldColor) return; // 先判断颜色,可能越界访问 if (x < 0 || x >= n || y < 0 || y >= m) return; // ... }
// ✅ 正确写法 voidfloodFill(int x, int y, char oldColor, char newColor){ if (x < 0 || x >= n || y < 0 || y >= m) return; // 先判断边界 if (g[x][y] != oldColor) return; // ... }
错误3:使用标记数组但未初始化
1 2 3 4 5 6 7 8 9 10 11
// ❌ 错误写法 bool st[N][N]; // 未初始化,可能包含随机值
// ✅ 正确写法 bool st[N][N] = {false}; // 初始化为false // 或者在使用前初始化 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { st[i][j] = false; } }