Files
python/TangDou/AcWing/DCC/T103492.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

65 lines
2.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10, M = 4e6 + 10;
int n, m;
int dfn[N], low[N], ts, root, stk[N], top;
vector<int> dcc[N];
int dcc_cnt;
//链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
//点双连通分量 模板
void tarjan(int u) {
dfn[u] = low[u] = ++ts; //分配时间戳
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 x; //利用栈,维护此连通块中所有的点
do {
x = stk[top--];
dcc[dcc_cnt].push_back(x);
} while (x != j);
dcc[dcc_cnt].push_back(u); // u是割点,也必须属于其它连通块,不能用了拉倒,需要再次入栈
}
} else
low[u] = min(low[u], dfn[j]);
}
}
int main() {
memset(h, -1, sizeof h);
scanf("%d %d", &n, &m);
for (int i = 0; i < m; i++) {
int a, b;
scanf("%d %d", &a, &b);
if (a != b) add(a, b), add(b, a); //此题目需要判断一下自环,否则1和11会挂
}
//给定一个n个点m条边的无向图,求该图中的所有点双连通分量(v-dcc)
for (root = 1; root <= n; root++) //每个点做为根结点进行枚举
if (!dfn[root]) tarjan(root);
// printf("%d\n", dcc_cnt);
for (int i = 1; i <= dcc_cnt; i++) { //枚举每个双连通分量
// printf("%d ", dcc[i].size());
for (int j = 0; j < dcc[i].size(); j++) //输出双连通分量中的点有哪些
printf("%d ", dcc[i][j]);
puts("");
}
return 0;
}