Tarjan 求割边割点

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;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值