Tarjan 求割边割点

来源:互联网 发布:sql server怎么导入表 编辑:程序博客网 时间:2024/06/06 17:23

Tarjan是多种算法的总称,因为Tarjan这个人太牛*了,那我们今天就来看一看Tarjan神的算法之一 :Tarjan求割边割点;

首先我们要清晰什么是割边割点:

割点:

首先我们有一张连通图:
这里写图片描述

对于这张图,显然它是一张联通图,那么割点的定义就是:“某一个点A,若删除这个点并且删去这个点所连的边,那么这张图的强联通分量增多”;

所以我们可以根据定义来推断出上图中的点3和点4是该图的割点,因为原图中的一个强联通分量是{1,2,3,4,5,6},若删除点3及相连的边后,强联通分量就变成了{1,2}和{4,5,6} (点3已删除);


那么割边呢?

显然,根据割点的定义,割边的定义可以推得:“某一条边B,若删除该边,则所在图的强联通分量增多”;这个定义和割点的定义极其相似;

则,在上图中,若删除3—4这条边,改图的强联通分量数目改变,由{1,2,3,4,5,6}—>{1,2,3}和{4,5,6};所以,该图中3—4这条边就是该图的割边;


同样,一个图中的割点割边有时候不止一个;

所以我们在处理时,应该用一个for来保证每个点都遍历到;


作为一个程序员,我们看重的不能只有思想,还要有代码:

#include<iostream>#include<cstdio>#include<vector>#define II int #define R register #define I 30001 using namespace std;struct node {    II up,to;}aa[I];II n,m,_num,root,_tot;II fa[I],vis[I],DFN[I],LOW[I],bit[I],head[I];void add(R II x,R II y){    aa[++_tot].up=head[x];    aa[_tot].to=y;    head[x]=_tot;}void Tarjan(R II x){    R II child=0;    DFN[x]=LOW[x]=++_num;    for(R II i=head[x];i;i=aa[i].up)    {        R II go=aa[i].to;        if(!DFN[go]){            child++;            fa[go]=x;            Tarjan(go);            if(LOW[go]>DFN[x]) ...            // x 和 go所连的边是一条割边;             LOW[x]=min(LOW[go],LOW[x]);            if(LOW[go]>=DFN[x]&&x!=root)  bit[x]=1;            // x 是根时 ,x 是一个割点;             if(x==root&&child>1)  bit[x]=1;            // x 不是根时 ,x 是割点;         }        else{            if(go!=fa[x]){                LOW[x]=min(LOW[x],DFN[go]);            }        }    }}int main(){    scanf("%d%d",&n,&m);    for(R II i=1;i<=m;i++)    {        R II x;R II y;        scanf("%d%d",&x,&y);        add(x,y);    }    for(R II i=1;i<=n;i++)    {        if(!DFN[i]){            root=i;            Tarjan(i);        }    }    for(R II i=1;i<=n;i++)    {        if(bit[i]){            //当bit[i]为真时,节点i为割点;             cout<<i<<" ";        }    }     return 0;}//#include<aTm>

我没有写割边的输出,留读者自己思考;

by pretend-fal;

END;