You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}