无向图的割点与桥

版权声明:2018/4/10重启blog;转载请注明出处 https://blog.csdn.net/zhaiqiming2010/article/details/82119082

定义

对于无向连通图G=(V,E),Tarjan算法可以在线性时间内求出无向图的割点和桥。

割点:对于x∈V,如果删除某个点x,图的联通分量增多(G分裂为两个或者两个以上的子图),则x为割点。

桥    :对于e∈E,如果删除e,G分裂成两个不相连的子图,则称e为桥或割边。

时间戳(T[i]):DFS的过程中,第一次访问到节点的时间,将N个节点依次标记为1-N。

搜索树:按照DFS的顺序建树。

追溯值(low[i]):low[i] = min(T[i通过不在搜索树上的边到达的点] , i的子树中的节点)。

割边判定法则:当节点x的子节点y满足T[x] < low[y] 时,边(x,y)为桥。  证明:当T[x] < T[y] 时 y走除了(x,y)外的任意边都无法到达时间戳更小的节点。

桥一定是搜索树中的边,简单环中的边一定都不是桥。

模板

#include <bits/stdc++.h>
using namespace std;


const int maxn = 1e5+10;
int dfn[maxn],low[maxn],n,num,tot,m;
int head[maxn],ver[maxn<<1],Next[maxn<<1];
bool bridge[maxn<<1];


void add(int x , int y)
{
    ver[++tot] = y,Next[tot]=head[x],head[x] = tot;
}
void Tarjan(int x, int in_edge)
{
    dfn[x] = low[x] =  ++num;
    for(int i = head[x] ; i ; i = Next[i])
    {
        int y = ver[i];
        if(!dfn[y])
        {
            Tarjan(y,i);
            low[x] = min(low[x],low[y]);

            if(low[y] > dfn[x])
            {
                bridge[i] = bridge[i^1] = true;
            }
        }
        else if(i != (in_edge^1))
        {
            low[x] = min(low[x] , dfn[y]);
        }
    }
}

int main()
{
    cin >> n >> m;
//    num = 0;
    tot = 1;
    for(int i = 0 ; i < m ; i++)
    {
        int x,y;
        cin >> x >> y;
        add(x,y);add(y,x);
    }

    for(int i = 1 ; i <= n ; i++)
    {
        if(!dfn[i])
            Tarjan(i,0);
    }

    for(int i = 2 ; i < tot ; i += 2 )
    {
        if(bridge[i])printf("%d %d\n",ver[i^1],ver[i]);
    }
}

猜你喜欢

转载自blog.csdn.net/zhaiqiming2010/article/details/82119082