Hướng giải của Lộ Trình Thông Tin


Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.

Tác giả: kienadmin

Lời giải

Bài toán yêu cầu đếm số đường đi trên đồ thị co (condensation DAG) từ SCC chứa đỉnh \(1\) đến SCC chứa đỉnh \(N\).

Các bước thực hiện:

  1. Dùng Tarjan tìm SCC của đồ thị.
  2. Xây dựng đồ thị co (DAG) từ các SCC.
  3. Sắp xếp topo trên DAG bằng thuật toán Kahn.
  4. Dùng quy hoạch động: \(dp[u]\) là số đường đi từ \(s\) đến \(u\). Với mỗi cạnh \(u \rightarrow v\), cập nhật \(dp[v] += dp[u]\).

Độ phức tạp: \(O(N + M)\).

Mã nguồn C++

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;

vector<vector<int>> adj;
vector<int> disc, low, comp;
vector<bool> inStack;
stack<int> st;
int timer, sccCnt;

void tarjan(int u) {
    disc[u] = low[u] = ++timer;
    st.push(u);
    inStack[u] = true;
    for (int v : adj[u]) {
        if (!disc[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (inStack[v]) {
            low[u] = min(low[u], disc[v]);
        }
    }
    if (low[u] == disc[u]) {
        sccCnt++;
        while (true) {
            int v = st.top(); st.pop();
            inStack[v] = false;
            comp[v] = sccCnt;
            if (v == u) break;
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n, m;
    cin >> n >> m;
    adj.resize(n + 1);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
    }
    disc.assign(n + 1, 0);
    low.assign(n + 1, 0);
    comp.assign(n + 1, 0);
    inStack.assign(n + 1, false);
    timer = 0; sccCnt = 0;
    for (int i = 1; i <= n; i++) {
        if (!disc[i]) tarjan(i);
    }

    vector<vector<int>> cond(sccCnt + 1);
    vector<int> inDeg(sccCnt + 1, 0);
    for (int u = 1; u <= n; u++) {
        for (int v : adj[u]) {
            if (comp[u] != comp[v]) {
                cond[comp[u]].push_back(comp[v]);
                inDeg[comp[v]]++;
            }
        }
    }

    int s = comp[1], t = comp[n];
    vector<long long> dp(sccCnt + 1, 0);
    dp[s] = 1;
    queue<int> q;
    for (int i = 1; i <= sccCnt; i++) {
        if (inDeg[i] == 0) q.push(i);
    }
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : cond[u]) {
            dp[v] = (dp[v] + dp[u]) % MOD;
            inDeg[v]--;
            if (inDeg[v] == 0) q.push(v);
        }
    }
    cout << dp[t] << "\n";
    return 0;
}

Nhận xét

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