http://hihocoder.com/contest/hiho53/problem/1
求出边的双联通分量
与求割点与割边类似,求边的双联通分量找的是桥,有m桥,那么就有m+1的分组。
而分组有点类似割边,如果一个分组中存在割边那么这个分组就不是分组,所以这张图的割边就是分组的边界,不包括在分组中,而low[u] == cur[u]正是割边所在的点,这是利用栈和DFS,把u后面入栈的点全部划分成同一分组,这样就写完了
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int Mod = 1e9 + 7;
const int maxn = 1e5 + 5;
const double eps = 0.00000001;
const int INF = 0x3f3f3f3f;
struct Edge{
int v, next;
}edge[maxn << 1];
int tot, head[maxn];
int parent[maxn], vis[maxn], low[maxn], cur[maxn], trace[maxn];
int top, sta[maxn], cnt;
void init() {
cnt = top = tot = 0;
memset(head, -1, sizeof(head));
memset(parent, -1, sizeof(parent));
memset(vis, 0, sizeof(vis));
}
void addEdge(int u, int v) {
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot ++;
edge[tot].v = u;
edge[tot].next = head[v];
head[v] = tot ++;
}
void DFS(int u) {
static int counter = 0;
int child = 0;
vis[u] = 1;
cur[u] = low[u] = ++counter;
sta[++ top] = u;
for (int i = head[u]; i + 1; i = edge[i].next) {
int v = edge[i].v;
if(!vis[v]) {
child ++;
parent[v] = u;
DFS(v);
low[u] = min(low[u], low[v]);
if(cur[u] < low[v]) {
cnt ++;
//printf("bridge: %d %d\n", u, v);
}
}else if(v != parent[u])
low[u] = min(low[u], cur[v]);
}
if(low[u] >= cur[u]) {
int tt = top;
int minn = u;
while(sta[tt] != u) {
minn = min(minn, sta[tt]);
tt --;
}
while(sta[top] != u) {
trace[sta[top]] = minn;
top --;
}
if(sta[top] == u) {
trace[u] = minn;
top --;
}
}
}
int main()
{
init();
int N, M;
cin >> N >> M;
while(M --) {
int u, v;
cin >> u >> v;
addEdge(u, v);
}
DFS(1);
cout << cnt + 1<< endl;
for (int i = 1; i <= N; i ++)
cout << trace[i] << " ";
cout << endl;
return 0;
}