双连通分量 模板

  1. bcc的全称是biconnected component,双连通分量,点双连通关注的是不包含割点的连通分量,边双连通关注的是不包含桥的连通分量。
  2. 点双连通例题:UVALive 5135。边双连通例题:poj 3352。
  3. 边双连通分量巧妙利用isB数组,空间换时间,也大大降低了模板的复杂度,解决了标记边难的问题。
//点双连通分量
bool cut[maxn];
int low[maxn], dfn[maxn], bccno[maxn], clocks, bcc_cnt;
vector<int> G[maxn], bcc[maxn];
stack 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();//bcc >= 1;
                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);
        }
    }
}

你可能感兴趣的:(算法竞赛,算法竞赛模板,图论)