割点和割边

割点和割边

给出一个无向连通图, 求出所有割点与割边的数量。

输入

第1行: 2个整数N,M (1 <= N <= 5,000,N-1 <= M <= 10,000),分别表示顶点数和边数 
接下来M行,每行2个整数,表示图中的一条边。

输出

第1行:1个整数,表示割点数
第2行:1个整数,表示割边数

样例输入

11 13
1 2
1 4
1 5
1 6
2 11
2 3
4 3
4 9
5 8
5 7
6 7
7 10
11 3

样例输出

4
3

概念

割点的定义(均在无向图中):在一个连通图中,如果有一个顶点集合,删除这个集合中的点以及相关的边之后,连通块的数量会增多.我们就称这个顶点集合为割点集合.如果这个点集合中只有一个点,那么这个点就叫做割点.
割边的定义(均在无向图中):在一个连通图中,如果删去其中一条边后,连通块的数量会增多,那么我们称这条边为桥或者是割边.

Tarjan算法

首先选择一个根节点,从它开始进行DFS遍历.
对于根节点来说,判断它是否为割点是十分容易的.我们只需要看它的字树的数量即可.若它的子树的数量>=2,那么它必定为一个割点.(使得子树与子树之间失去了联系)
那么我们只需要求非根节点是否为割点即可.
首先,我们需要定义两个数组:low[]和dfn[].
dfn[u]为u点在上述dfs中是被访问到的第几个点。
low[u]为从u点及u点的子孙出发仅经过一次回边能到达的最小dfn。(如上图low[2]=1 2>3>1)

割点

如果一条边满足low[v]>=dfn[u],那么u点即为一个割点.
证明:如果存在这样一条边满足这样的性质,那么u的儿子v就永远不会访问到早于u的点,那么也就是说,从v出发形成的环中不会包括u,那么从u断开的话,就会形成两个或多个连通块,满足了割点的需求.
首先,low[u]可以先初始化为dfn[u],我们认为u至少能通过回边访问到自己(其实也就是没有回边).然后我们在遍历的过程中,考虑两种情况:一种是v点还没有被访问过,那么它的low[u]=min(low[u],low[v])(此时low[v]已经在dfs的过程中求出来了(在回溯的过程中),v能访问到的最早的点u同样也能访问到).
在过程中如果访问到一个已经访问过的点,那么有low[u]=min(low[u],dfn[v]).然后返回.

割边

割边的求法类似于割点.之前我们说到,在判断非根节点是否为割点时,我们采用了看low[v]>=dfn[u]的做法,在这里我们的做法更加简单.
不需要考虑根节点的问题,只需要判定low[v]>dfn[u]即可.(如之前给出来的图)

Code

#include<cstdio>  
#include<vector> 
using namespace std; 
#define MAXN 5001 
vector<int>G[MAXN]; 
int Dfn[MAXN],Low[MAXN];  
bool Vis[MAXN];  
int n,m; 
int cp=0,ce=0,dcnt=0,rtson=0;//计数器
//cp点数 ce边数  
//dcnt当前点的发现时间(第一次遍历到的序号)
//rtson
inline int Min(int x,int y){//取两数较小  
    return x<y?x:y;    
}  
void Dfs(int u,int fa){//当前节点与父亲节点
    Low[u]=Dfn[u]=++dcnt;//Low值初值与Dfn一样
    for(int i=0;i<G[u].size();i++){ //枚举相连点
        int v=G[u][i];
        if(!Dfn[v]){//没有遍历过  
            Dfs(v,u);//搜索
            /*回溯处理*/
            Low[u]=Min(Low[u],Low[v]);//更新Low值  
            if(Low[v]>=Dfn[u]){ //判断割点 
                if(fa!=-1){  
                    if(!Vis[u]){  //判重
                        cp++;  
                        Vis[u]=true;  
                    } 
                } 
                else rtson++;     
            }  
            if(Low[v]>Dfn[u])ce++; //判断割边
        }  
        else if(v!=fa) 
            Low[u]=Min(Low[u],Dfn[v]); 
    }  
}  
int main(){  
    scanf("%d%d",&n,&m);  
    for(int i=0;i<m;i++){  
        int u,v;  
        scanf("%d%d",&u,&v); 
        G[u].push_back(v); //邻接矩阵
        G[v].push_back(u); 
    }  
    Dfs(1,-1);  
    if(rtson>1)cp++;  
    printf("%d\n%d\n",cp,ce);     
}  

猜你喜欢

转载自blog.csdn.net/qq_38956769/article/details/79526132
今日推荐