- bcc的全称是biconnected component,双连通分量,点双连通关注的是不包含割点的连通分量,边双连通关注的是不包含桥的连通分量。
- 点双连通例题:UVALive 5135。边双连通例题:poj 3352。
- 边双连通分量巧妙利用isB数组,空间换时间,也大大降低了模板的复杂度,解决了标记边难的问题。
bool cut[maxn];
int low[maxn], dfn[maxn], bccno[maxn], clocks, bcc_cnt;
vector<int> G[maxn], bcc[maxn];
stack<Edge> S;
void tarjan(int u, int fa){
low[u] = dfn[u] = ++clocks;
int child = 0;
for(int i = 0; i < G[u].size(); ++i){
int v = G[u][i];
Edge e = Edge(u, v);
if(!dfn[v]){
S.push(e);
child++;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
cut[u] = true;
bcc_cnt++; bcc[bcc_cnt].clear();
while(1){
Edge t = S.top(); S.pop();
if(bccno[t.u] != bcc_cnt){
bcc[bcc_cnt].push_back(t.u);
bccno[t.u] = bcc_cnt;
}
if(bccno[t.v] != bcc_cnt){
bcc[bcc_cnt].push_back(t.v);
bccno[t.v] = bcc_cnt;
}
if(t.u==u && t.v==v) break;
}
}
}
else if(fa!=v && low[u]>dfn[v]) {
S.push(e);
low[u] = dfn[v];
}
}
if(fa==-1)
cut[u] = (child>=2) ? true : false;
}
const int maxn = 1005;
int n, times, bcc_cnt, dfn[maxn], low[maxn], bccno[maxn];
vector<int> G[maxn];
bool isB[maxn][maxn];
void tarjan(int u, int fa){
dfn[u] = low[u] = ++times;
for(int i = 0; i < G[u].size(); ++i){
int v = G[u][i];
if(!dfn[v]){
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] > dfn[u])
isB[u][v] = isB[v][u] = true;
}
else if(fa != v)
low[u] = min(low[u], dfn[v]);
}
}
void dfs(int idx){
dfn[idx] = 1;
bccno[idx] = bcc_cnt;
for(int i = 0; i < G[idx].size(); ++i){
int v = G[idx][i];
if(isB[idx][v])
continue;
if(!dfn[v])
dfs(v);
}
}
void find_ebcc(){
bcc_cnt = times = 0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(bccno,0,sizeof(bccno));
memset(isB,0,sizeof(isB));
for(int i = 1; i <= n; ++i){
if(!dfn[i]){
bcc_cnt++;
tarjan(i, -1);
}
}
memset(dfn,0,sizeof(dfn));
for(int i = 1; i <= n; ++i){
if(!dfn[i]){
bcc_cnt++;
dfs(i);
}
}
}