连通分量合集

tarjan算法求连通分量的核心还是聚类,为每个节点设置后续遍历序号dfn、节点最早追溯序号low

low(u) = min(low(v))(v 为 u 后续)

low(u) = min(dfn(v))(u 为 v 后续)

low(u)= min(low(u),dfn(u))

桥(u,v): low(v) > dfn(u)

割点 u : 

u为根 & 子树大于1

u不为根 & 存在边(u,v)使dfn(u)<= low(v)

块:在该点集内的点没有桥

块与块之间通过桥连通

入度,出度:对于压缩点后的有向图来说,每个点均有入度出度,若某个点存在入度或出度为0,则该点必不可能处于其他强连通分量内

int block, idx, low[MAXN], dfn[MAXN], vis[MAXN];
void tarjan ( int u ) {
    int v;
    low[u] = dfn[u] = idx++;
    for ( int i = head[u]; ~i; i = edge[i].next ) {
        v = edge[i].to;
        // 无向图
        if ( vist[i >> 1] ) {
            continue;
        }
        vist[i >> 1] = 1;
        if ( !dfn[v] ) {
            tarjan ( v );
            low[u] = min ( low[u], low[v] );
            block += dfn[u] < low[v];
        } else if ( dfn[v] < low[u] ) {
            low[u] = dfn[v];
        }
    }
}

确定每个点所属块,可引入模拟堆栈

int block, top, mstk[MAXN], isin[MAXN], idx, low[MAXN], dfn[MAXN], belong[MAXN];
void tarjan ( int u ) {
    int v;
    mstk[top++] = u;
    isin[u] = 1;
    low[u] = dfn[u] = ++idx;
    for ( int i = head[u]; ~i; i = edge[i].next ) {
        v = edge[i].to;
        if ( !dfn[v] ) {
            tarjan ( v );
            low[u] = min ( low[u], low[v] );
        } else if ( isin[v] && dfn[v] < low[u] ) {
            low[u] = dfn[v];
        }
    }
    if ( low[u] == dfn[u] ) {
        block++;
        do {
            v = mstk[--top];
            isin[v] = 0;
            belong[v] = block;
        } while ( v != u );
    }
}

上述代码中 isin[v]  仅在有向图中有用


在连通分支内寻找环、割点

void tarjan ( int u ) {
    int v, k;
    mstk[top++] = u;
    low[u] = dfn[u] = ++idx;
    for ( int i = head[u]; ~i; i = edge[i].next ) {
        if ( vis[i >> 1] ) {
            continue;
        }
        vis[i >> 1] = 1;
        v = edge[i].to;
        if ( !dfn[v] ) {
            tarjan ( v );
            low[u] = min ( low[u], low[v] );
            if ( low[v] >= dfn[u] ) {
                block = 0;
                clr(isin);
                do {
                    k = mstk[--top];
                    isin[k] = 1;
                    pnum[block++] = k;
                } while ( k != v );
                pnum[block++] = u;
                isin[u] = 1;
                getCount();
            }
        } else if ( dfn[v] < low[u] ) {
            low[u] = dfn[v];
        }
    }
}




入门题:hdu 1269 http://acm.hdu.edu.cn/showproblem.php?pid=1269

基础题:hdu 2767 http://acm.hdu.edu.cn/showproblem.php?pid=2767

     hdu 3072 http://acm.hdu.edu.cn/showproblem.php?pid=3072

提高题:hdu 3394 http://acm.hdu.edu.cn/showproblem.php?pid=3394

应用题(树DP):hdu 4612 http://acm.hdu.edu.cn/showproblem.php?pid=4612

     hdu 3639 http://acm.hdu.edu.cn/showproblem.php?pid=3639


你可能感兴趣的:(连通分量合集)