Tarjan算法杂谈

以后写无向图最好都记录一下来边from,不要记录father,因为前者更有通用性。


对于一个点双连通分量\(G\),除非该连通子图只有一个点,否则\(G\)至少有两个点。

证明:

只有一个点的情况,显然 \(|G|=1\)

如果点数至少有两个:

随便取两个点,构成一个子图\(E\)

根据定义,删去给图中任意一个点,都不会使图不连通,所以这是一个点双连通子图。由于点双连通分量是极大点双连通子图,所以其点数一定不少于2个。

边双连通分量中两点之间都至少包含在一个简单环中。

这个定理可以用来判简单环。

Tarjan的LCA用的不多。

有向图的强连通分量:

void tarjan(int u)
{
    dfn[u] = low[u] = ++ timestamp;
    stk[ ++ top] = u;
    in_stk[u] = true;
    
    for (int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if (!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (in_stk[v]) low[u] = min(low[u], low[v]);
    }
    
    if (dfn[u] == low[u])
    {
        ++ scc_cnt;
        int y;
        do 
        {
            y = stk[top -- ];
            in_stk[y] = false;
            id[y] = scc_cnt;
            sz[scc_cnt] ++ ;
        } while (y != u);
    }
}

无向图的点双连通分量:

注意事项:坑点记录2022.11.10。

void tarjan(int u, int from)
{
    dfn[u] = low[u] = ++ timestamp;
    stk[ ++ top] = u;
    
    int cnt = 0;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if (!dfn[v])
        {
            cnt ++ ;
            tarjan(v, i);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u])
            {
                if (root != u || cnt > 1) cut[u] = true;
                ++ vdcc_cnt;
                int y;
                do {
                    y = stk[top -- ];
                    vdcc[vdcc_cnt].push_back(y);
                } while (y != v);
                vdcc[vdcc_cnt].push_back(u);
            }
        }
        else if (i != (from ^ 1))
            low[u] = min(low[u], dfn[v]);
    }
    
    if (u == root && !cnt)
    {
        ++ vdcc_cnt;
        top -- ;
        vdcc[vdcc_cnt].push_back(u);
    }
}

无向图的边双连通分量

void tarjan(int u, int from)
{
    dfn[u] = low[u] = ++ timestamp;
    stk[ ++ top] = u;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if (!dfn[v])
        {
            tarjan(v, i);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) isbrg[i] = isbrg[i ^ 1] = true;
        }
        else if (i != (from ^ 1)) low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u])
    {
        ++ dcc_cnt;
        int y;
        do {
            y = stk[top -- ];
            dcc[dcc_cnt].push_back(y);
        } while (y != u);
    }
}
posted @ 2022-11-10 21:30  Zlc晨鑫  阅读(28)  评论(0)    收藏  举报