T103492 【模板】點雙連通分量
阿新 • • 發佈:2022-04-04
實現程式碼
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10, M = 2 * N; int dfn[N], low[N]; int n, m; int timestamp, root; int stk[N], top; // tarjan用的棧 vector<int> dcc[N]; int dcc_cnt; //鄰接表 int e[M], h[N], idx, ne[M]; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } //點雙連通分量 模板 void tarjan(int u) { dfn[u] = low[u] = ++timestamp; //分配時間戳 stk[++top] = u; // u入棧 if (u == root && h[u] == -1) { // 根,而且沒有出邊,孤立點 dcc[++dcc_cnt].push_back(u); // 分量數++ return; } for (int i = h[u]; ~i; i = ne[i]) { //列舉u的每條邊 int j = e[i]; if (!dfn[j]) { //如果j沒有被走過 tarjan(j); // dfs low[u] = min(low[u], low[j]); //用兒子的low[j]嘗試更新low[u] if (low[j] >= dfn[u]) { //如果u是割點 dcc_cnt++; //連通塊增加 int y; //利用棧,維護此連通塊中所有的點 do { y = stk[top--]; dcc[dcc_cnt].push_back(y); } while (y != j); dcc[dcc_cnt].push_back(u); // u是割點,也必須屬於其它連通塊,不能用了拉倒,需要再次入棧 } } else low[u] = min(low[u], dfn[j]); } } int main() { memset(h, -1, sizeof h); cin >> n >> m; for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; add(a, b), add(b, a); } //給定一個n個點m條邊的無向圖,求該圖中的所有點雙連通分量(v-dcc) for (root = 1; root <= n; root++) //每個點做為根結點進行列舉 if (!dfn[root]) tarjan(root); for (int i = 1; i <= dcc_cnt; i++) { //列舉每個雙連通分量 for (int j = 0; j < dcc[i].size(); j++) //輸出雙連通分量中的點有哪些 printf("%d ", dcc[i][j]); puts(""); } return 0; }