割点与桥模板

算法:

dfn【u】为dfs遍历中u是第几个被访问到的。

low【u】为该dfs u可以到达的访问时间最早的祖先的深度。

首先,对图进行一次dfs遍历,可以得到每个点的dfn和low。

考察所有点u和它在dfs树中的儿子节点s1,s2……sk。

(1)如果对于某个si,满足low[si]>=dfn[u],那么u是一个割点;

(2)如果对于某个si,满足low[si]>dfn[u],那么边(u,si)是一个桥。

对于搜索树的根节点,还需要特殊判断一下:如果根有且仅有一个儿子节点,那么根肯定不是割点。

模板:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
const int MAX_V = 1000;
const int MAX_E = 1000000;

int vis[MAX_V]; //结点v当前访问状态,0表示未访问,1表示在栈中,2表示已经访问过
int dfn[MAX_V]; //结点v被访问时的深度
int low[MAX_V]; //结点v可以到达的访问时间最早的祖先的深度
bool cut[MAX_V];
bool bridge[MAX_V][MAX_V];
//cur是割点的条件:①cur是根且有大于一个儿子; ②cur不是根且cur有一个儿子v使low[v]>=dfn[cur];
//(cur, i)是桥的条件:low[i] > dfn[cur];
void cut_bridge(int cur, int father, int dep, int n) //vertex: 0~n-1
{
    vis[cur] = 1;
    dfn[cur] = dep;
    low[cur] = dep;
    int children = 0;
    for(int i = 0; i < n; i++)
    {
        if(edge[cur][i]) //与当前节点相连的结点i
        {
            if(i != father && vis[i] == 1) //i在当前栈中,说明图中有一个环,用i的深度更新cur的low值;
            {
                if(dfn[i] < low[cur]) low[cur] = dfn[i]; //将结点cur可以到达的访问时间最早的祖先的深度更新为结点i被访问时的深度;
            }
            if(vis[i] == 0) //i没被访问过,递归访问节点i,并用i的可以到达的最早祖先来更新cur的low值;
            {
                cut_bridge(i, cur, dep+1, n);
                children ++;

                if(low[i] < low[cur]) low[cur] = low[i];
                if((father == -1 && children > 1) || (father == -1 && low[i] >= dfn[cur])) //判断割点
                        cut[cur] = true;
                if(low[i] > dfn[cur]) bridge[cur][i] = bridge[i][cur] = true;             //判断桥
            }
        }
    }
    vis[cur] = 2;
}
//对于每一个连通块取一个点x调用cut_bredge(x,-1,0,n),其中n为点数。

猜你喜欢

转载自blog.csdn.net/Dilly__dally/article/details/81415525