算法笔记——连通分量

本文深入探讨图论中的重要概念,包括如何判断无向边是否为桥,割点的判定法则,以及双连通分量的特性。通过深度优先搜索算法,可以有效地寻找图的连通分量、桥和割点,并进行双连通分量的缩点操作。对于非联通图,需要遍历每个连通分量进行分析。理解这些概念对于图的分析和处理至关重要。

 

 

 

 

 注意追溯点的定义是通过非父子边追溯

 桥判定法则:无向边x-y是桥,当且仅当搜索树上存在x的子节点y,满足low[y]>dfn[x]

也就是说,若孩子的low值比自己的dfn值大,则从该节点到这个孩子的边为桥

low[y]>dfn[x]表示孩子没有其他路径可以返回父节点或更前的节点处,因此父子边为连接这两个节点的唯一边,即为桥

割点判定法则:若x不是根节点,则x是割点,当且仅当在搜索树上存在x的子节点y,满足low[y]\geqslant dfn[x] ;若x是根节点,则x是割点,当且仅当搜索树上至少存在2个子节点满足以上条件

因为要把x点删掉,所以可以有等号,即最多到达父节点x

因为根是起点,没有父节点,所以需要两个子节点分支。

注意,以上提到的子节点都是与父亲直接连接的子节点

对于非联通图,要查找每一个连通分量进行dfs

for(int i=1;i<=n;i++)
    if(!dfn[i])
    {
        root=i;
        tarjan(i,0);//根节点父节点置为0,表示不存在
    }

查找桥

void tarjan(int x,int fa)
{
    low[x]=dfn[x]=++cnt;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa) continue;//不能从父亲边进入
        if(!dfn[y])
        {
            tarjan(y,x);
            low[x]=min(low[x],low[y]);
            if(low[y]>dfn[x])
                printf("%d->%d",x,y);
        }
        else low[x]=min(low[x],dfn[y]);
    }

}

查找割点

void tarjan(int x,int fa)
{
    int t=0;
    low[x]=dfn[x]=++cnt;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa) continue;//不能从父亲边进入
        if(!dfn[y])
        {
            tarjan(y,x);
            low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x])
            {
                t++;
                if(root!=x || t>=2) isCut[x]=true;
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }

}

 双连通分量任意两点间存在不同的路径。边双连通分量路径没有重复边,点双连通分量没有重复点(1、2个节点的点双连通分量除外)

双连通分量缩点

边双连通分量:将边双连通分量缩为点,用桥来连接缩成的节点

low值不同的节点属于不同的边双连通分量

void tarjan(int x,int fa)//边双连通分量缩点
{
    dfn[x]=low[x]=++dfscnt;
    sta[top++]=x;//将节点压入栈
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa) continue;
        if(!dfn[y])
        {
            tarjan(y,x);
            low[x]=min(low[x],low[y])
        }
        else if(!dccnum[y]) low[x]=min(low[x],dfn[y]);//已经出栈的不要
    }
    if(low[x]==dfn[x])//连通分量起点
    {
        dcccnt++;
        do
        {
            dccnum[sta[--top]]=dcccnt;
        }while(sta[top]!=x);
    }
}

点双连通分量:将点双连通分量缩为点,用割点连向有该割点存在的点双连通分量

 

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值