跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ DFS 与 BFS 算法实战详解

详细讲解了 C++ 中 DFS 与 BFS 算法的核心思想、实现方式及典型应用场景。内容涵盖递归与非递归实现、多源最短路、拓扑排序等进阶用法,并通过八皇后、迷宫、岛屿数量等经典例题展示代码细节。文章对比了两种算法在数据结构、时空复杂度及适用场景上的差异,旨在帮助开发者扎实掌握图论搜索基础,提升算法实战能力。

ApiHolic发布于 2026/3/24更新于 2026/10/2786 浏览
C++ DFS 与 BFS 算法实战详解

C++ DFS 与 BFS 算法实战详解

深度优先搜索(DFS)和广度优先搜索(BFS)是图论中最基础的两种遍历算法,也是解决路径、连通性、最短路等问题的核心工具。本文将结合 C++ 实现与经典例题,带你从原理到实战全面掌握这两种算法。

一、DFS(深度优先搜索)

1. 基本思想

DFS 的核心在于'一条路走到黑,不撞南墙不回头'。它会沿着某条分支尽可能深入,直到无法继续时回溯到上一个分叉点,尝试其他路径。实现上通常使用递归或显式栈。

2. 特点

  • 数据结构:栈(递归调用栈或手动维护的栈)。
  • 空间复杂度:取决于递归深度,最坏为 O(H)(H 为树的高度或图的深度)。
  • 时间复杂度:O(V + E),需遍历所有顶点和边。
  • 适用场景:路径搜索、连通性检测、回溯问题(如排列组合)、拓扑排序。

3. C++ 实现

非递归实现(显式栈)
void dfs_iterative(int start, vector<vector<int>>& graph) {
    stack<int> st;
    vector<bool> visited(graph.size(), false);
    st.push(start);
    visited[start] = true;
    while (!st.empty()) {
        int u = st.top();
        st.pop();
        for (int v : graph[u]) {
            if (!visited[v]) {
                visited[v] = true;
                st.push(v);
            }
        }
    }
}
递归实现(以图的遍历为例)
void dfs(int u, vector<bool>& visited, vector<vector<int>>& graph) {
    visited[u] = true;
    for (int v : graph[u]) {
        if (!visited[v]) {
            dfs(v, visited, graph);
        }
    }
}

4. 经典例题

例题 1:八皇后(洛谷 P1219)

思路:利用二进制位运算优化状态标记,快速判断列及斜线冲突。

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

int n;
#define MASK(n) ((1 << (n + 1)) - 2)
unordered_map<int, int> ind;
int tot = 3;
int arr[20];

void out() {
    for (int i = 1; i <= n; i++) {
        if (i > 1) cout << " ";
        printf("%d", arr[i]);
    }
    printf("\n");
    tot--;
    return;
}

int dfs(int i, int t1, int t2, int t3) {
    if (i > n) {
        if (tot) out();
        return 1;
    }
    int ans = 0;
    for (int t = t1; t; t -= (-t & t)) {
        int j = ind[-t & t];
        if ((t2 & (1 << (i + j - 1))) && (t3 & (1 << (i - j + n)))) {
            arr[i] = j;
            ans += dfs(i + 1, t1 ^ (1 << j), t2 ^ (1 << (i + j - 1)), t3 ^ (1 << (i - j + n)));
        }
    }
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < 2 * n; i++) ind[1 << i] = i;
    int ans = dfs(1, MASK(n), MASK(2 * n - 1), MASK(2 * n - 1));
    cout << ans << "\n";
    return 0;
}
例题 2:奇怪的电梯(洛谷 P1135)

思路:记录到达每层的最少按钮数 dis[],若当前步数 k 大于等于已记录的 dis[a],则剪枝返回。

#include <iostream>
using namespace std;
const int N = 205;
int to[N], dis[N];
int n;

void dfs(int k, int a) {
    if (dis[a] <= k) return;
    dis[a] = k;
    if (a + to[a] <= n) dfs(k + 1, a + to[a]);
    if (a - to[a] >= 1) dfs(k + 1, a - to[a]);
}

int main() {
    int a, b; cin >> n >> a >> b;
    for (int i = 1; i <= n; i++) {
        cin >> to[i];
        dis[i] = n + 1;
    }
    dfs(0, a);
    printf("%d\n", dis[b] == n + 1 ? -1 : dis[b]);
    return 0;
}
例题 3:选数(洛谷 P1036)

思路:标准的组合型枚举,dfs(u, ind, sum) 分别表示已选数量、起始索引、当前和值。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 25;
int a[N];
int n, k;
long long ans = 0;

bool is_prime(int x) {
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i++) {
        if (x % i == 0) return false;
    }
    return true;
}

void dfs(int u, int ind, int sum) {
    if (u == k) {
        if (is_prime(sum)) ans++;
        return;
    }
    for (int i = ind; i <= n; i++) {
        dfs(u + 1, i + 1, sum + a[i]);
    }
}

int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) cin >> a[i];
    dfs(0, 1, 0);
    printf("%lld\n", ans);
    return 0;
}
例题 4:迷宫(洛谷 P1605)

思路:技巧性地给地图外围加障碍(初始化为 1),内部障碍设为 0,避免边界判断。

#include <iostream>
using namespace std;
const int N = 7;
int g[N][N];
int n, m, t, sx, sy, ex, ey;
int ans = 0;
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

void dfs(int x, int y) {
    if (x == ex && y == ey) {
        ans++;
        return;
    }
    g[x][y] = 0;
    for (int i = 0; i < 4; i++) {
        int dx = x + dir[i][0], dy = y + dir[i][1];
        if (g[dx][dy] == 0) continue;
        dfs(dx, dy);
    }
    g[x][y] = 1;
}

int main() {
    cin >> n >> m >> t;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) g[i][j] = 1;
    }
    cin >> sx >> sy >> ex >> ey;
    for (int i = 0; i < t; i++) {
        int x, y; cin >> x >> y;
        g[x][y] = 0;
    }
    dfs(sx, sy);
    cout << ans << "\n";
    return 0;
}
例题 5:吃奶酪(洛谷 P1433)

思路:状态压缩 DP 结合 DFS,记录剩余奶酪集合和当前位置。

#include <iostream>
#include <cmath>
using namespace std;
const int N = 17;
double ans = 1e9;
int n;
double x[N], y[N];
double dis[N][N];
double dp[70000][20];
int ind[70000];

double d(int i, int j) {
    return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}

void dfs(int t, int now, double s) {
    if (t == 0) {
        if (s < ans) ans = s;
        return;
    }
    for (int k = t; k; k -= (k & -k)) {
        int to = ind[k & -k], next_t = t - (1 << to);
        double l = s + dis[now][to];
        if (dp[next_t][to] != 0 && dp[next_t][to] <= l) continue;
        dp[next_t][to] = l;
        if (ans <= l) continue;
        dfs(next_t, to, l);
    }
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> n;
    x[0] = y[0] = 0;
    for (int i = 1; i <= n; i++) cin >> x[i] >> y[i];
    for (int i = 0; i <= n; i++) {
        for (int j = i; j <= n; j++) dis[i][j] = dis[j][i] = d(i, j);
    }
    for (int k = 1, i = 0; i <= N; i++, k *= 2) ind[k] = i;
    dfs((1 << (n + 1)) - 2, 0, 0);
    printf("%.2lf\n", ans);
    return 0;
}
例题 6:单词搜索(LeetCode 79)

思路:常规 DFS,注意匹配失败时需回溯标记数组。

int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int n, m;
bool st[505][505];

bool dfs(vector<vector<char>>& board, string word, int x, int y, int pos) {
    if (pos == word.size()) return true;
    for (int i = 0; i < 4; i++) {
        int dx = x + dir[i][0], dy = y + dir[i][1];
        if (dx >= 0 && dx < n && dy >= 0 && dy < m && board[dx][dy] == word[pos] && !st[dx][dy]) {
            st[dx][dy] = true;
            if (dfs(board, word, dx, dy, pos + 1)) return true;
            st[dx][dy] = false;
        }
    }
    return false;
}

bool exist(vector<vector<char>>& board, string word) {
    n = board.size(), m = board[0].size();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (board[i][j] == word[0]) {
                st[i][j] = true;
                if (dfs(board, word, i, j, 1)) return true;
                st[i][j] = false;
            }
        }
    }
    return false;
}

二、BFS(广度优先搜索)

1. 基本思想

BFS 通过队列逐层扩展搜索,保证先访问离起点最近的节点。其核心是'地毯式搜索,层层推进',适用于无权图的最短路径问题。

2. 特点

  • 数据结构:队列。
  • 空间复杂度:O(V)(最坏情况存储所有顶点)。
  • 时间复杂度:O(V + E)。
  • 适用场景:无权图最短路径、层级遍历、广播网络、二分图检测。

3. C++ 实现

void bfs(int start, vector<vector<int>>& graph) {
    queue<int> q;
    vector<bool> visited(graph.size(), false);
    q.push(start);
    visited[start] = true;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int v : graph[u]) {
            if (!visited[v]) {
                visited[v] = true;
                q.push(v);
            }
        }
    }
}

4. 经典例题

例题 1:马的遍历(洛谷 P1443)

思路:马走日有 8 个方向,使用 BFS 层序遍历求最短步长,DFS 会超时。

#include <iostream>
#include <queue>
using namespace std;
const int N = 405;
int dir[8][2] = {
    {2, 1}, {-2, 1}, {2, -1}, {-2, -1},
    {1, 2}, {1, -2}, {-1, 2}, {-1, -2}
};
int dis[N][N];
int n, m;
struct Node {
    int x, y, s;
    Node(int _x, int _y, int _s) : x(_x), y(_y), s(_s) {}
};

void bfs(int a, int b) {
    queue<Node> q;
    q.push(Node(a, b, 0));
    dis[a][b] = 0;
    while (!q.empty()) {
        Node now = q.front();
        q.pop();
        for (int k = 0; k < 8; k++) {
            int dx = now.x + dir[k][0], dy = now.y + dir[k][1];
            if (dx < 1 || dx > n) continue;
            if (dy < 1 || dy > m) continue;
            if (dis[dx][dy] != -1) continue;
            q.push(Node(dx, dy, now.s + 1));
            dis[dx][dy] = now.s + 1;
        }
    }
}

int main() {
    int a, b; cin >> n >> m >> a >> b;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) dis[i][j] = -1;
    }
    bfs(a, b);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) cout << dis[i][j] << " ";
        cout << "\n";
    }
    return 0;
}
例题 2:迷宫离入口最近的出口(LeetCode 1296)

思路:层序遍历时记录层数,找到边界 '.' 即为最短距离。

int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
    int n = maze.size(), m = maze[0].size();
    queue<pair<int, int>> q;
    q.push({entrance[0], entrance[1]});
    vector<vector<int>> vis(n, vector<int>(m));
    vis[entrance[0]][entrance[1]] = true;
    int ans = 0;
    while (!q.empty()) {
        ans++;
        int size = q.size();
        while (size--) {
            auto [x, y] = q.front();
            q.pop();
            for (int k = 0; k < 4; k++) {
                int dx = x + dir[k][0], dy = y + dir[k][1];
                if (dx >= 0 && dx < n && dy >= 0 && dy < m && !vis[dx][dy] && maze[dx][dy] == '.') {
                    if (dx == 0 || dx == n - 1 || dy == 0 || dy == m - 1) return ans;
                    q.push({dx, dy});
                    vis[dx][dy] = true;
                }
            }
        }
    }
    return -1;
}
例题 3:最小基因变化(LeetCode 433)

思路:将字符串变换抽象为图的最短路,BFS 即可。

int minMutation(string startGene, string endGene, vector<string>& bank) {
    unordered_set<string> vis;
    unordered_set<string> hash(bank.begin(), bank.end());
    if (startGene == endGene) return 0;
    if (!hash.count(endGene)) return -1;
    string change = "ACGT";
    queue<string> q;
    q.push(startGene);
    vis.insert(startGene);
    int ret = 0;
    while (!q.empty()) {
        ret++;
        int size = q.size();
        while (size--) {
            string t = q.front();
            q.pop();
            for (int i = 0; i < 8; i++) {
                string tmp = t;
                for (int j = 0; j < change.size(); j++) {
                    tmp[i] = change[j];
                    if (hash.count(tmp) && !vis.count(tmp)) {
                        if (tmp == endGene) return ret;
                        q.push(tmp);
                        vis.insert(tmp);
                    }
                }
            }
        }
    }
    return -1;
}
例题 4:单词接龙(LeetCode 127)

思路:类似上题,每次改变一个字符。

int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
    unordered_set<string> hash(wordList.begin(), wordList.end());
    unordered_set<string> vis;
    if (hash.count(endWord) == 0) return 0;
    queue<string> q;
    q.push(beginWord);
    vis.insert(beginWord);
    int ret = 1;
    while (!q.empty()) {
        ret++;
        int size = q.size();
        while (size--) {
            string t = q.front();
            q.pop();
            for (int i = 0; i < t.size(); i++) {
                string tmp = t;
                for (char ch = 'a'; ch <= 'z'; ch++) {
                    tmp[i] = ch;
                    if (hash.count(tmp) && !vis.count(tmp)) {
                        if (tmp == endWord) return ret;
                        q.push(tmp);
                        vis.insert(tmp);
                    }
                }
            }
        }
    }
    return 0;
}
例题 5:为高尔夫比赛砍树(LeetCode 675)

思路:按高度排序后,依次计算相邻两棵树间的最短路并累加。

int m, n;
bool vis[55][55];
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

int bfs(vector<vector<int>>& forest, int bx, int by, int ex, int ey) {
    if (bx == ex && by == ey) return 0;
    queue<pair<int, int>> q;
    memset(vis, 0, sizeof(vis));
    q.push({bx, by});
    vis[bx][by] = true;
    int step = 0;
    while (!q.empty()) {
        step++;
        int size = q.size();
        while (size--) {
            auto [a, b] = q.front();
            q.pop();
            for (int i = 0; i < 4; i++) {
                int x = a + dir[i][0], y = b + dir[i][1];
                if (x >= 0 && x < n && y >= 0 && y < m && forest[x][y] && !vis[x][y]) {
                    if (x == ex && y == ey) return step;
                    q.push({x, y});
                    vis[x][y] = true;
                }
            }
        }
    }
    return -1;
}

int cutOffTree(vector<vector<int>>& forest) {
    n = forest.size(), m = forest[0].size();
    vector<pair<int, int>> trees;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (forest[i][j] > 1) trees.push_back({i, j});
        }
    }
    sort(trees.begin(), trees.end(), [&](const pair<int, int> x, const pair<int, int> y) {
        return forest[x.first][x.second] < forest[y.first][y.second];
    });
    int bx = 0, by = 0;
    int ret = 0;
    for (auto& [a, b] : trees) {
        int step = bfs(forest, bx, by, a, b);
        if (step == -1) return -1;
        ret += step;
        bx = a, by = b;
    }
    return ret;
}

5. 多源最短路 BFS

当存在多个起点时,将所有起点同时入队,视为同一层的扩展源。

例题 1:01 矩阵(LeetCode 542)

思路:从所有 0 开始向外扩散,第一次遇到 1 时的层数即为最短距离。

int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
    int n = mat.size(), m = mat[0].size();
    vector<vector<int>> dist(n, vector<int>(m, -1));
    queue<pair<int, int>> q;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (mat[i][j] == 0) {
                dist[i][j] = 0;
                q.push({i, j});
            }
        }
    }
    while (!q.empty()) {
        auto [a, b] = q.front();
        q.pop();
        for (int k = 0; k < 4; k++) {
            int x = a + dir[k][0], y = b + dir[k][1];
            if (x >= 0 && x < n && y >= 0 && y < m && dist[x][y] == -1) {
                dist[x][y] = dist[a][b] + 1;
                q.push({x, y});
            }
        }
    }
    return dist;
}
例题 2:飞地的数量(LeetCode 1020)

思路:正难则反,从边界上的 1 开始 BFS,标记所有能连到边界的 1,剩下的即为飞地。

int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int numEnclaves(vector<vector<int>>& grid) {
    int n = grid.size(), m = grid[0].size();
    vector<vector<bool>> vis(n, vector<bool>(m));
    queue<pair<int, int>> q;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if ((i == 0 || i == n - 1 || j == 0 || j == m - 1) && grid[i][j] == 1) {
                q.push({i, j});
                vis[i][j] = true;
            }
        }
    }
    while (!q.empty()) {
        auto [a, b] = q.front();
        q.pop();
        for (int k = 0; k < 4; k++) {
            int x = a + dir[k][0], y = b + dir[k][1];
            if (x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && grid[x][y] == 1) {
                q.push({x, y});
                vis[x][y] = true;
            }
        }
    }
    int ret = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == 1 && !vis[i][j]) ret++;
        }
    }
    return ret;
}
例题 3:地图上的最高点(LeetCode 1765)

思路:01 矩阵变体,从所有水域(0)开始 BFS。

int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {
    int n = isWater.size(), m = isWater[0].size();
    vector<vector<int>> dist(n, vector<int>(m, -1));
    queue<pair<int, int>> q;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (isWater[i][j]) {
                dist[i][j] = 0;
                q.push({i, j});
            }
        }
    }
    while (!q.empty()) {
        auto [a, b] = q.front();
        q.pop();
        for (int k = 0; k < 4; k++) {
            int x = a + dir[k][0], y = b + dir[k][1];
            if (x >= 0 && x < n && y >= 0 && y < m && dist[x][y] == -1) {
                dist[x][y] = dist[a][b] + 1;
                q.push({x, y});
            }
        }
    }
    return dist;
}
例题 4:地图分析(LeetCode 1162)

思路:从所有陆地(1)开始 BFS,找最远的海洋(0)。

int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int maxDistance(vector<vector<int>>& grid) {
    int n = grid.size(), m = grid[0].size();
    vector<vector<int>> dist(n, vector<int>(m, -1));
    queue<pair<int, int>> q;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j]) {
                dist[i][j] = 0;
                q.push({i, j});
            }
        }
    }
    int ret = -1;
    while (!q.empty()) {
        auto [a, b] = q.front();
        q.pop();
        for (int k = 0; k < 4; k++) {
            int x = a + dir[k][0], y = b + dir[k][1];
            if (x >= 0 && x < n && y >= 0 && y < m && dist[x][y] == -1) {
                dist[x][y] = dist[a][b] + 1;
                q.push({x, y});
                ret = max(ret, dist[x][y]);
            }
        }
    }
    return ret;
}

6. BFS 解决拓扑排序

例题 1:课程表(LeetCode 207)

思路:入度为 0 的点入队,出队时减少邻居入度,新产生的 0 入度点入队。

bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    vector<vector<int>> adj(numCourses);
    vector<int> d(numCourses, 0);
    queue<int> q;
    for (auto e : prerequisites) {
        int u = e[0], v = e[1];
        adj[u].emplace_back(v);
        d[v]++;
    }
    for (int i = 0; i < numCourses; i++) {
        if (d[i] == 0) q.push(i);
    }
    int cnt = 0;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        cnt++;
        for (auto v : adj[u]) {
            if (--d[v] == 0) q.push(v);
        }
    }
    return cnt == numCourses;
}
例题 2:课程表 II(LeetCode 210)

思路:同上,记录出队顺序。

vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
    vector<vector<int>> adj(numCourses);
    vector<int> d(numCourses, 0);
    for (auto e : prerequisites) {
        int v = e[0], u = e[1];
        adj[u].push_back(v);
        d[v]++;
    }
    queue<int> q;
    for (int i = 0; i < numCourses; i++) {
        if (d[i] == 0) q.push(i);
    }
    vector<int> ans;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        ans.push_back(u);
        for (auto v : adj[u]) {
            if (--d[v] == 0) q.push(v);
        }
    }
    return ans.size() != numCourses ? vector<int>() : ans;
}
例题 3:火星词典(LeetCode LCR 114)

思路:根据字典序建图,判断是否有环(拓扑排序)。注意处理前缀相同的情况。

unordered_map<char, unordered_set<char>> edges;
unordered_map<char, int> in;

bool add(string &s1, string &s2) {
    int n = min(s1.size(), s2.size());
    int i = 0;
    for (; i < n; i++) {
        if (s1[i] != s2[i]) {
            char a = s1[i], b = s2[i];
            if (!edges.count(a) || !edges[a].count(b)) {
                edges[a].insert(b);
                in[b]++;
            }
            break;
        }
    }
    if (i == s2.size() && i < s1.size()) return true;
    return false;
}

string alienOrder(vector<string>& words) {
    for (auto &s : words) {
        for (auto &ch : s) in[ch] = 0;
    }
    int n = words.size();
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (add(words[i], words[j])) return "";
        }
    }
    queue<char> q;
    for (auto &[a, b] : in) {
        if (b == 0) q.push(a);
    }
    string ret;
    while (!q.empty()) {
        char t = q.front();
        q.pop();
        ret += t;
        for (auto ch : edges[t]) {
            if (--in[ch] == 0) q.push(ch);
        }
    }
    for (auto &[a, b] : in) {
        if (b != 0) return "";
    }
    return ret;
}

三、对比

特性DFSBFS
数据结构栈(递归/非递归)队列
空间复杂度O(H)(路径深度)O(V)(存储所有节点)
最短路径不保证(可能找到非最短解)保证(无权图最短路径)
适用场景路径存在性、回溯问题最短路径、层级遍历
内存消耗较低(适合深树)较高(适合宽图)

经典例题对比 -- FloodFill 算法

图像渲染(LeetCode 733)

两种方法均可,DFS 代码更简洁,BFS 避免栈溢出风险。

岛屿数量(LeetCode 200)

遍历矩阵,遇到 '1' 即启动一次搜索(DFS/BFS)标记整个岛屿。

岛屿的最大面积(LeetCode 695)

在搜索过程中统计连通区域大小,取最大值。

四、总结

  • DFS 适合探索所有可能性或路径存在性问题,但对最短路径不敏感,需注意递归深度限制。
  • BFS 保证无权图最短路径,但内存消耗较大,适合层级相关的问题。
  • 实战技巧:组合使用 DFS 和 BFS(如 IDA*),剪枝优化(尤其在 DFS 中),双向 BFS 加速搜索。

使用场景建议:

  1. DFS:迷宫探索、图的连通分量、全排列生成、复杂状态转移。
  2. BFS:社交网络六度空间、二叉树层次输出、病毒传播模拟、二分图检测。

掌握这两种基础算法,是解决更复杂图论问题的基石。在实际编码中,根据题目对'最短'、'全部'、'层级'的要求灵活选择即可。

目录

  1. C++ DFS 与 BFS 算法实战详解
  2. 一、DFS(深度优先搜索)
  3. 1. 基本思想
  4. 2. 特点
  5. 3. C++ 实现
  6. 非递归实现(显式栈)
  7. 递归实现(以图的遍历为例)
  8. 4. 经典例题
  9. 例题 1:八皇后(洛谷 P1219)
  10. 例题 2:奇怪的电梯(洛谷 P1135)
  11. 例题 3:选数(洛谷 P1036)
  12. 例题 4:迷宫(洛谷 P1605)
  13. 例题 5:吃奶酪(洛谷 P1433)
  14. 例题 6:单词搜索(LeetCode 79)
  15. 二、BFS(广度优先搜索)
  16. 1. 基本思想
  17. 2. 特点
  18. 3. C++ 实现
  19. 4. 经典例题
  20. 例题 1:马的遍历(洛谷 P1443)
  21. 例题 2:迷宫离入口最近的出口(LeetCode 1296)
  22. 例题 3:最小基因变化(LeetCode 433)
  23. 例题 4:单词接龙(LeetCode 127)
  24. 例题 5:为高尔夫比赛砍树(LeetCode 675)
  25. 5. 多源最短路 BFS
  26. 例题 1:01 矩阵(LeetCode 542)
  27. 例题 2:飞地的数量(LeetCode 1020)
  28. 例题 3:地图上的最高点(LeetCode 1765)
  29. 例题 4:地图分析(LeetCode 1162)
  30. 6. BFS 解决拓扑排序
  31. 例题 1:课程表(LeetCode 207)
  32. 例题 2:课程表 II(LeetCode 210)
  33. 例题 3:火星词典(LeetCode LCR 114)
  34. 三、对比
  35. 经典例题对比 -- FloodFill 算法
  36. 图像渲染(LeetCode 733)
  37. 岛屿数量(LeetCode 200)
  38. 岛屿的最大面积(LeetCode 695)
  39. 四、总结

更多推荐文章

查看全部
  • 结构化思维:ChatGPT 如何实现高效信息管理
  • 前后端分离架构 vs 传统架构:核心差异与选型指南
  • Flink History Server 查看已完成作业 Web UI 与 REST 数据
  • GitHub Copilot Agent Skills:打造跨项目 AI 专属工具箱
  • OpenClaw 刚配好就完了?5 步调教,让你的 AI 助手真正“能干活”
  • PC 微信 4.1.5.16 UI 树隐藏问题:UIAutomation 修复与自动化实战
  • Whisper-large-v3 多任务并行:转录/翻译/摘要一体化服务
  • FunASR:阿里巴巴开源语音识别工具包及部署教程
  • Ubuntu ISO 镜像下载地址汇总
  • AI 时代产品经理的能力边界:AI 能做什么与不能做什么
  • OpenClaw gateway start 报 401 错误:环境变量配置问题
  • Python 工业传感器异常检测与五大核心算法解析
  • 大语言模型(LLM)研究进展与展望
  • 从 LLaMA-Factory 微调到高通 NPU 部署:Qwen-0.6B 全链路移植指南
  • 洛谷 B2132 素数对 C++ 题解
  • 基于 AI 辅助的在线图书借阅平台设计与实现
  • ComfyUI ControlNet 模型推荐清单(2025 版)
  • 测试驱动开发(TDD)核心流程与 Java 实战
  • Python 基础核心知识点详解:从数据类型到面向对象编程
  • RAG 工程实践拦路虎之一:PDF 格式解析杂谈

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online