图论——连通无向图的双连通性

定义补充

一个连通的无向图如果不存在被删除之后使得剩下的图不再连通的顶点,那么这样的无向连通图称为双连通

如果一个图不是双连通的,那么将其删除使得图不再连通的那些顶点叫做割点

背向边:指在深度优先搜索中如果v搜索到了已知点w,则称存在一条v到w的背向边,代表存在一个环

求割点

深度优先搜索提供一种找出连通图中所有割点的线性时间算法请添加图片描述
如图是一个连通图,首先,从图中任意顶点开始,执行深度优先搜索并在顶点被访问时给他编号,对于每一个顶点v我们称其先序编号为Num[v],然后对于深度优先搜索生成树上的每一个结点v,计算其顶点的Low[v],该点从v开始通过树的零条或者多条边且可能还有一条背向边而到达。

这里给出Low[v]的定义
Low[v]是
1.Num[v](不选取边)
2.所有背向边(v,w)中最低的Num[w](不选去树的边而选取一条背向边)
3.树的所有边(v,w)中最低的Low[w](选择树的某些边以及可能一条背向边,可用一个递归简明描述)
中的最小值
在这里插入图片描述
此图为上图的深度优先搜索树,箭头方向为搜索方向,虚线为背向边,每个字母旁边有两个数值Num[v]/Low[v]

通过对图的分析我们知道,如果我们想要计算出Low[v],我们必须计算出所有v的儿子的Low[w],因此这是一个后序遍历,对于任意的一条边(v,w),我们只需要检查Num[v]和Num[w]就可以知道它是树的一条边还是一条背向边

接下来我们用这些信息找出割点,根是割点当且仅当它有多于一个的儿子,如果他有两个儿子,那么删除根会使得结点不连通而分布在不同的子树上,对于其他任何节点v,它是割点当且仅当它有某个儿子w使得Low[w]>=Num[v]

注意:这个条件在根处总是满足的,因此需要进行特殊判断

下面给出三个例程
1、对顶点的Num赋值的伪代码

int counter=1;
void AssignNum(Vertex V)//V是起始点,即为根
{
    Vertex W;
    Num[V]=counter++;
    Visit[V]=true;
    for each W adjacent to V
    {
        if(Visit[W]==false)
        {
            Parent[W]=V;//记录前驱
            AssignNum(W);//Dfs下一个节点
        }
    }
}

2、计算Low并检验是否为割点的伪代码

void AssignLow(Vertex V)
{
    Vertex W;
    Low[V]=Num[V];//规则一
    for each W adjacent to V
    {
        if(Num[W]>=Num[V])//正向边
        {
            AssignLow(W);//向下搜索
            if(Low[W]>=Num[V])
            {
                printf("V is an articulation point");//V是割点
            }
            Low[V]=min(Low[V],Low[W]);//规则三
        }
        else
        {
            if(Parent[V]!=W)//背向边
            Low[V]=min(Low[V],Num[W]);//规则二 
        }
    }

}

3.在一次深度优先搜索(忽略对根的检测)中对割点的检测

void FindArt(Vertex V)
{
    Vertex W;
    Visit[V]=true;
    Low[V]=Num[V]=counter++;
    for each W adjcent to V
    {
        if(!Visit[W])
        {
            Parent[W]=V;
            FindArt(W);
            if(Low[W]>=Num[V])
            {
                printf("V is an articulation point");//V是割点
            }
            Low[V]=min(Low[V],Low[W]);
        }
        else{
            if(Parent[V]!=W)
            {
                Low[V]=min(Low[V],Num[W]);
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要获取无向图双连通分量,可以使用Tarjan算法。以下是一个Python实现的示例代码: ``` def tarjan_biconnected_components(graph): """ Tarjan算法计算无向图双连通分量 :param graph: 无向图,用邻接列表表示 :return: 双连通分量列表 """ index_counter = [0] stack = [] lowlink = {} index = {} result = [] bridges = [] def strongconnect(node): # 为节点赋予唯一的索引 index[node] = index_counter[0] lowlink[node] = index_counter[0] index_counter[0] += 1 stack.append(node) # 对于每个相邻节点v for v in graph[node]: # 如果v没有被访问过,则递归调用strongconnect if v not in index: strongconnect(v) lowlink[node] = min(lowlink[node], lowlink[v]) # 如果v是一个桥,则将桥添加到bridges列表中 if lowlink[v] == index[v]: bridges.append((node, v)) # 如果v已经在堆栈中,则更新此节点的lowlink elif v in stack: lowlink[node] = min(lowlink[node], index[v]) # 如果节点是一个连接分量的根,则弹出堆栈,并收集连通分量 if lowlink[node] == index[node]: connected_component = [] while True: v = stack.pop() connected_component.append(v) if v == node: break result.append(connected_component) for node in graph: if node not in index: strongconnect(node) return result ``` 使用示例: ``` graph = { 1: {2, 3}, 2: {1, 3, 4}, 3: {1, 2, 4}, 4: {2, 3, 5}, 5: {4} } result = tarjan_biconnected_components(graph) print(result) # 输出:[[1, 2, 3], [4, 5]] ``` 以上代码实现了Tarjan算法,用于计算无向图双连通分量。传入的图以邻接列表表示,返回的结果是双连通分量的列表。对于结果中的每个双连通分量,其包含的节点组成了一个强连通分量,即任意两个节点都有一条路径相连。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青云遮夜雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值