Lý thuyết đồ thị


đã đăng vào 1 tháng 4 năm 2025, 12:33 a.m.

🌐 Cheatsheet Chi Tiết: Lý Thuyết Đồ Thị & Cây (Graph & Tree Theory)


🧠 Khái Niệm Cơ Bản

Thuật ngữ Mô tả
Đỉnh (vertex) Một nút trong đồ thị hoặc cây
Cạnh (edge) Kết nối giữa hai đỉnh
Bậc (degree) Số cạnh nối vào một đỉnh (in/out degree với đồ thị có hướng)
Đường đi (path) Chuỗi đỉnh nối nhau bằng cạnh
Chu trình (cycle) Đường đi bắt đầu và kết thúc tại cùng một đỉnh
Cây (tree) Đồ thị vô hướng, liên thông, không chu trình
DAG Đồ thị có hướng không có chu trình (Directed Acyclic Graph)

📌 Ứng Dụng Đồ Thị & Cây

  • Tìm đường đi ngắn nhất: giao thông, mạng máy tính (Dijkstra, BFS)
  • Tối ưu mạng lưới: xây dựng cây khung nhỏ nhất (Kruskal, Prim)
  • Phân tích cấu trúc: SCC, Biconnected, Cầu/Khớp (Tarjan, Kosaraju)
  • Quản lý phân cấp: tổ chức, biểu đồ thừa kế → dùng cây
  • Truy vấn tổ tiên, phân đoạn cây: LCA, HLD, Euler Tour

🎯 Biểu Diễn Đồ Thị

Danh sách kề (Adjacency List) — Thường dùng
vector<vector<int>> adj(n + 1);
adj[u].push_back(v);
Ma trận kề (Adjacency Matrix) — Chỉ dùng khi đồ thị dày
vector<vector<int>> g(n + 1, vector<int>(n + 1, 0));
g[u][v] = 1;
DSU — Dùng trong Kruskal, Union-Find
vector<int> parent(n + 1);
iota(parent.begin(), parent.end(), 0);

int find(int u) {
    return u == parent[u] ? u : parent[u] = find(parent[u]);
}

void unite(int u, int v) {
    parent[find(u)] = find(v);
}

🔄 Duyệt Đồ Thị

DFS (Depth-First Search)
void dfs(int u) {
    visited[u] = true;
    for (int v : adj[u])
        if (!visited[v]) dfs(v);
}
BFS (Breadth-First Search)
void bfs(int start) {
    queue<int> q;
    q.push(start);
    visited[start] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : adj[u])
            if (!visited[v]) {
                visited[v] = true;
                q.push(v);
            }
    }
}

🌲 DFS Trên Cây — Truy Vết, Kích Thước, Chiều Sâu

vector<int> parent(n + 1), depth(n + 1), size(n + 1);

void dfs_tree(int u, int p) {
    parent[u] = p;
    size[u] = 1;
    depth[u] = depth[p] + 1;
    for (int v : adj[u]) {
        if (v == p) continue;
        dfs_tree(v, u);
        size[u] += size[v];
    }
}

📉 Tìm Tổ Tiên Chung Gần Nhất (LCA - Binary Lifting)

const int LOG = 20;
int up[MAXN][LOG], tin[MAXN], tout[MAXN], timer;

void dfs_lca(int u, int p) {
    tin[u] = ++timer;
    up[u][0] = p;
    for (int i = 1; i < LOG; ++i)
        up[u][i] = up[up[u][i - 1]][i - 1];
    for (int v : adj[u])
        if (v != p) dfs_lca(v, u);
    tout[u] = ++timer;
}

bool is_ancestor(int u, int v) {
    return tin[u] <= tin[v] && tout[v] <= tout[u];
}

int lca(int u, int v) {
    if (is_ancestor(u, v)) return u;
    if (is_ancestor(v, u)) return v;
    for (int i = LOG - 1; i >= 0; --i)
        if (!is_ancestor(up[u][i], v))
            u = up[u][i];
    return up[u][0];
}

📚 Khi Nào Dùng Kỹ Thuật Nào?

Nhu cầu Thuật toán / Kỹ thuật
Duyệt đồ thị DFS / BFS
Đếm thành phần liên thông DFS
Tìm đường ngắn nhất BFS (đơn vị), Dijkstra
Tìm tổ tiên chung (LCA) Binary Lifting / RMQ
Cây khung nhỏ nhất Kruskal / Prim
Tìm chu trình DFS + back edge
Phân tích cấu trúc Tarjan, SCC, Bridge, AP
Truy vấn trên đường đi hoặc cây con Euler Tour + Segment Tree
Cập nhật động trên cây HLD, Link Cut Tree (nâng cao)

📈 Độ Phức Tạp Tổng Hợp

Thuật toán Thời gian Không gian
DFS / BFS O(V + E) O(V + E)
Kruskal (với DSU) O(E log E) O(V)
Dijkstra (PQ) O((V + E) log V) O(V + E)
Tarjan (SCC, cầu, khớp) O(V + E) O(V + E)
LCA (binary lifting) O(log N) O(N log N)

📚 Tham Khảo

  • CP-Algorithms - Graph Theory
  • CSES Graph & Tree Algorithms
  • AtCoder Educational DP Contest (Tree DP)
  • VNOI / SPOJ / Codeforces Tag "graphs", "trees"

Nhận xét

Không có ý kiến tại thời điểm này.