返回首页 C++ 模板

图论基础

图的存储、DFS/BFS遍历、Flood Fill——图论从零开始

邻接表 DFS BFS FloodFill GESP7
#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
const int M = 500010;

// ========== 1. 邻接矩阵存储 ==========
int g_mat[510][510];  // 适合稠密图,节点数 ≤ 500

// ========== 2. 邻接表存储 ==========
vector<int> adj[N];         // 无权图
vector<pair<int,int>> adjw[N]; // 带权图:{邻居, 权重}

void add_edge(int u, int v) {
    adj[u].push_back(v);
    adj[v].push_back(u);  // 无向图加这行
}

// ========== 3. 图的 DFS 遍历 ==========
bool vis[N];

void graph_dfs(int u) {
    vis[u] = true;
    cout << u << " ";
    for (int v : adj[u]) {
        if (!vis[v]) graph_dfs(v);
    }
}

// ========== 4. 图的 BFS 遍历 ==========
void graph_bfs(int start, int n) {
    memset(vis, false, sizeof(vis));
    queue<int> q;
    q.push(start);
    vis[start] = true;

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        cout << u << " ";

        for (int v : adj[u]) {
            if (!vis[v]) {
                vis[v] = true;
                q.push(v);
            }
        }
    }
}

// ========== 5. 连通性判断 ==========
int count_components(int n) {
    memset(vis, false, sizeof(vis));
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            graph_dfs(i);
            cnt++;
        }
    }
    return cnt;
}

// ========== 6. 环检测(无向图)==========
bool has_cycle_dfs(int u, int parent) {
    vis[u] = true;
    for (int v : adj[u]) {
        if (!vis[v]) {
            if (has_cycle_dfs(v, u)) return true;
        } else if (v != parent) {
            return true;  // 访问过且不是父节点 → 有环
        }
    }
    return false;
}

bool has_cycle(int n) {
    memset(vis, false, sizeof(vis));
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            if (has_cycle_dfs(i, -1)) return true;
        }
    }
    return false;
}

// ========== 7. Flood Fill(泛洪算法)==========
// 网格版:从种子点扩散,标记连通区域
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

void flood_fill(vector<vector<int>> &grid, int x, int y, int newColor) {
    int oldColor = grid[x][y];
    if (oldColor == newColor) return;

    int n = grid.size(), m = grid[0].size();
    queue<pair<int,int>> q;
    q.push({x, y});
    grid[x][y] = newColor;

    while (!q.empty()) {
        auto [cx, cy] = q.front();
        q.pop();

        for (int d = 0; d < 4; d++) {
            int nx = cx + dx[d], ny = cy + dy[d];
            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            if (grid[nx][ny] != oldColor) continue;
            grid[nx][ny] = newColor;
            q.push({nx, ny});
        }
    }
}

// Flood Fill 计算连通块数量
int count_regions(vector<string> &grid) {
    int n = grid.size(), m = grid[0].size();
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    int cnt = 0;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == '#' && !visited[i][j]) {
                cnt++;
                queue<pair<int,int>> q;
                q.push({i, j});
                visited[i][j] = true;
                while (!q.empty()) {
                    auto [x, y] = q.front();
                    q.pop();
                    for (int d = 0; d < 4; d++) {
                        int nx = x + dx[d], ny = y + dy[d];
                        if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                        if (visited[nx][ny] || grid[nx][ny] != '#') continue;
                        visited[nx][ny] = true;
                        q.push({nx, ny});
                    }
                }
            }
        }
    }
    return cnt;
}

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

    int n, m;
    cin >> n >> m;  // n个节点,m条边
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        add_edge(u, v);
    }

    cout << "DFS: ";
    memset(vis, false, sizeof(vis));
    graph_dfs(1);
    cout << endl;

    cout << "BFS: ";
    graph_bfs(1, n);
    cout << endl;

    cout << "连通分量数: " << count_components(n) << endl;

    return 0;
}

📖 要点说明

图的两种存储方式

方式 空间 适用 优缺点
邻接矩阵 O(n²) 稠密图 n≤500 简单但空间大
邻接表 O(n+m) 稀疏图 节省空间,竞赛首选

DFS vs BFS 遍历图

对比项 DFS BFS
数据结构 递归/栈 队列
用途 连通性、环检测、路径 最短路(无权图)
空间 O(n) O(n)

Flood Fill

⚠️ 常见错误

🎮 动手试试

理解判断逻辑,图遍历中大量使用条件判断: