总览
就是通过tarjan算法,将走过的边都变成有向边,不准往回走,看能不能构成强连通分量,如果可以的话,就满足是双连通分量,通过遍历完之后low[k]是否大于dfn[u]来确定.
例题
acwing 395.冗余路径(割边)
题目要求对一个图添加边,使成为双连通分量,先通过tarjan缩点,缩完之后只剩下一棵树,再对树的叶子节点,也就是只连一条边的点进行连边,答案就是(叶子节点+1)/2,注意用^1的方法取对边的话,边要从0开始计数。
代码如下
#include <bits/stdc++.h>
#include <windows.h>
using namespace std;
const int N = 5 * 1e3 + 5,M = 4 * N;
struct Edge{
int to,next;
}e[M];
int h[N];
int dfn[N],low[N];
int in_stk[N],timestamp;
int id[N];
int dcc_cnt,idx;
int is_bridge[M];
int d[N];
stack <int> st;
void add(int fr,int to){
e[idx].to = to;
e[idx].next = h[fr];
h[fr] = idx;
idx ++;
}
void tarjan(int u,int from){
dfn[u] = low[u] = ++ timestamp;
in_stk[u] = true;
st.push(u);
for(int i = h[u];~i;i = e[i].next){
int k = e[i].to;
if(! dfn[k]){
tarjan(k,i);
low[u] = min(low[u],low[k]);
if(low[k] > dfn[u]){
is_bridge[i] = true;
is_bridge[i ^ 1] = true;
}
}else if((i ^ 1) != from && in_stk[k]) low[u] = min(low[u],dfn[k]);
}
if(low[u] == dfn[u]){
++ dcc_cnt;
int y;
do{
y = st.top();
st