tarjan算法——求无向图的割点和桥

Tarjan算法求桥与割点
本文介绍如何使用Tarjan算法求解无向图中的桥与割点,包括算法的基本概念、实现原理及C++代码实现。

一.基本概念

1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥。
2.割点:无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。

二:tarjan算法在求桥和割点中的应用

1.割点:
1)当前节点为树根的时候,条件是“要有多余一棵子树”(如果这有一颗子树,去掉这个点也没有影响,如果有两颗子树,去掉这点,两颗子树就不连通了。)
2)当前节点U不是树根的时候,条件是“low[v]>=dfn[u]”,也就是在u之后遍历的点,能够向上翻,最多到u,如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。 保证v向上最多翻到u才可以
2.桥:若是一条无向边(u,v)是桥,
1)当且仅当无向边(u,v)是树枝边的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u–v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥。
如果v能上翻到u那么u–v就是一个环,删除其中一条路径后,能然是连通的。
3.注意点:
1)求桥的时候:因为边是无方向的,所以父亲孩子节点的关系需要自己规定一下,
在tarjan的过程中if(v不是u的父节点) low[u]=min(low[u],dfn[v]);
因为如果v是u的父亲,那么这条无向边就被误认为是环了。
2)找桥的时候:注意看看有没有重边,有重边的边一定不是桥,也要避免误判。
4.也可以先进行tarjan(),求出每一个点的dfn和low,并记录dfs过程中的每个点的父节点,遍历所有点的low,dfn来寻找桥和割点

三:求桥和割点的模板

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#include<vector>
#define N 201
vector<int>G[N];
int n,m,low[N],dfn[N];
bool is_cut[N];
int father[N];
int tim=0;
void input()
{
    scanf("%d%d",&n,&m);
    int a,b;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&a,&b);
        G[a].push_back(b);/*邻接表储存无向边*/
        G[b].push_back(a);
    }
}
void Tarjan(int i,int Father)
{
    father[i]=Father;/*记录每一个点的父亲*/
    dfn[i]=low[i]=tim++;
    for(int j=0;j<G[i].size();++j)
    {
        int k=G[i][j];
        if(dfn[k]==-1)
        {
            Tarjan(k,i);
            low[i]=min(low[i],low[k]);
        }
        else if(Father!=k)/*假如k是i的父亲的话,那么这就是无向边中的重边,有重边那么一定不是桥*/
            low[i]=min(low[i],dfn[k]);//dfn[k]可能!=low[k],所以不能用low[k]代替dfn[k],否则会上翻过头了。
    }
}
void count()
{
    int rootson=0;
    Tarjan(1,0);
    for(int i=2;i<=n;++i)
    {
        int v=father[i];
        if(v==1)
        rootson++;/*统计根节点子树的个数,根节点的子树个数>=2,就是割点*/
        else{
            if(low[i]>=dfn[v])/*割点的条件*/
            is_cut[v]=true;
        }
    }
    if(rootson>1)
    is_cut[1]=true;
    for(int i=1;i<=n;++i)
    if(is_cut[i])
    printf("%d\n",i);
    for(int i=1;i<=n;++i)
    {
        int v=father[i];
        if(v>0&&low[i]>dfn[v])/*桥的条件*/
        printf("%d,%d\n",v,i);
    }

}
int main()
{
    input();
    memset(dfn,-1,sizeof(dfn));
    memset(father,0,sizeof(father));
    memset(low,-1,sizeof(low));
    memset(is_cut,false,sizeof(is_cut));
    count();
    return 0;
}
### Tarjan算法无向图中的实现与原理 #### 1. 基本定义 在无向连通图 \( G = (V, E) \) 中,是指当移除某个顶及其所有关联边后,原图分裂为多个连通分量的节。而(或称为边),则是指删除某条边后,原图分裂为两个不相连的子图的那条边。 为了高效计算这些结构,Tarjan 提出了基于深度优先搜索(DFS)的方法来线性时间内找到所有的[^2]。 --- #### 2. 关键变量说明 在 Tarjan 算法中,主要依赖以下几个组: - **`dfn[x]`**: 表示节 `x` 被访问到的时间戳,在 DFS 遍历过程中依次递增赋值。 - **`low[x]`**: 表示从节 `x` 出发能回溯到的最早祖先节的时间戳。即通过某些路径可以到达的最小 `dfn` 值。 这两个变量用于判断当前节是否为或当前边是否为。 --- #### 3. 判断条件 ##### (1)判定 对于任意节 `x`: - 如果它是根节且至少有两个不同的子树,则它是一个。 - 如果它不是根节,存在其某一子节 `y` 满足 \( low[y] \geq dfn[x] \),则 `x` 是[^3]。 ##### (2)判定 对于一条有向边 `(x, y)`,如果满足 \( low[y] > dfn[x] \),那么这条边是一条[^4]。 --- #### 4. 实现细节 以下是 Tarjan 算法的核心伪代码描述: ```python def tarjan(u, parent): global time_stamp dfn[u] = low[u] = time_stamp time_stamp += 1 child_count = 0 is_cut_vertex = False for v in adjacency_list[u]: if not visited[v]: # 如果v未被访问过 visited[v] = True child_count += 1 tarjan(v, u) low[u] = min(low[u], low[v]) if parent != -1 and low[v] >= dfn[u]: is_cut_vertex = True if low[v] > dfn[u]: bridges.append((u, v)) elif v != parent: # 如果v已经被访问过且不是父节 low[u] = min(low[u], dfn[v]) if parent == -1 and child_count > 1: is_cut_vertex = True if is_cut_vertex: cut_vertices.add(u) time_stamp = 1 visited = [False] * n dfn = [-1] * n low = [-1] * n cut_vertices = set() bridges = [] for i in range(n): if not visited[i]: visited[i] = True tarjan(i, -1) ``` 上述代码实现了对整个无向图的一次遍历,并在此基础上标记出所有的。 --- #### 5. 时间复杂度分析 由于 Tarjan 算法仅需一次 DFS 即可完成全部操作,因此时间复杂度为 \( O(V + E) \),其中 \( V \) \( E \) 分别表示图中的节点数。 --- #### 6. 应用场景 该算法广泛应用于网络拓扑优化、社交网络分析等领域。例如: - 找出通信网络的关键节),以便加强冗余设计; - 发现交通路网中最脆弱的部分(梁),从而提升整体稳定性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值