图的割点与割边

割点

什么是割点?

如果在一个图中,如果把一个点删除,那么这个图不再联通,那么这个点就是割点(割顶),当然是在无向图。

如何实现?

如果我们尝试删除每个点,并且判断这个图的联通性,那么复杂度会特别的高。所以要介绍一个常用的算法:\(Tarjan\)。

首先,我们上一个图:

很容易的看出割点是 2,而且这个图仅有这一个割点。

首先,我们按照 \(DFS\) 序给他打上时间戳(访问的顺序)。

这些信息被我们保存在一个叫做 num 的数组中。

还需要另外一个数组 low,用它来存储不经过其父亲(你有多个那么就看你遍历到了哪个)能到达的时间戳。

例如 2 的话是 1, 5 和 6 是 3。

然后我们开始 \(DFS\),我们判断某个点是否是割点的根据是:对于某个顶点 \(u\),如果存在至少一个顶点 \(v\) ( \(u\) 的儿子),使得 \(low_v>=num_u\),即不能回到祖先,那么 \(u\) 点为割点。

另外,如果搜到了自己(在环中),如果他有两个及以上的儿子,那么他一定是割点了,如果只有一个儿子,那么把它删掉,不会有任何的影响。比如下面这个图,此处形成了一个环,从树上来讲它有 2 个儿子:

我们在访问 1 的儿子时候,假设先 \(DFS\) 到了 2,然后标记用过,然后递归往下,来到了 4, 4 又来到了 3,当递归回溯的时候,会发现 3 已经被访问过了,所以不是割点。

更新 low 的伪代码如下:

如果 v 是 u 的儿子
    low[u]=min(low[u],low[v]);
否则
    low[u] = min(low[u],num[v]);

洛谷 P3388 【模板】割点(割顶)

Code

/*
洛谷 P3388 【模板】割点(割顶)
算法: Tarjan
时间:2018 8 22
by @liyifeng
*/
#include<bits/stdc++.h>
using namespace std;
int n,m;//n:点数 m:边数
int num[100001],low[100001],inde,res;
//num:记录每个点的时间戳 low:能不经过父亲到达最小的编号,inde:时间戳,res:答案数量
bool vis[100001],flag[100001];//flag: 答案 vis:标记是否重复
vector <int> edge[100001];// 存图用的
void Tarjan(int u,int father)//u 当前点的编号,father 自己爸爸的编号
{
    vis[u]=true;// 标记
    low[u]=num[u]=++inde;// 打上时间戳
    int child=0;// 每一个点儿子数量
    for(auto v : edge[u])// 访问这个点的所有邻居 (C++11)
    {
        if(!vis[v])
        {
            child++;// 多了一个儿子
            Tarjan(v,u);// 继续
            low[u]=min(low[u],low[v]);// 更新能到的最小节点编号
            if(father!=u&&low[v]>=num[u]&&!flag[u])// 主要代码
            // 如果不是自己,且不通过父亲返回的最小点符合割点的要求,并且没有被标记过
            // 要求即为:删了父亲连不上去了,即为最多连到父亲
            {
                flag[u]=true;
                res++;// 记录答案
            }
        }
        else if(v!=father)
            low[u]=min(low[u],num[v]);// 如果这个点不是自己,更新能到的最小节点编号
    }
    if(father==u&&child>=2&&!flag[u])// 主要代码,自己的话需要 2 个儿子才可以
    {
        flag[u]=true;
        res++;// 记录答案
    }
}
int main()
{
    cin>>n>>m;// 读入数据
    for(int i=1;i<=m;i++)// 注意点是从 1 开始的
    {
        int x,y;
        cin>>x>>y;
        edge[x].push_back(y);
        edge[y].push_back(x);
    }// 使用 vector 存图
    for(int i=1;i<=n;i++)// 因为 Tarjan 图不一定联通
        if(!vis[i])
        {
            inde=0;// 时间戳初始为 0
            Tarjan(i,i);// 从第 i 个点开始,父亲为自己
        }
    cout<<res<<endl;
    for(int i=1;i<=n;i++)
        if(flag[i]) cout<<i<<" ";// 输出结果
    for(int i=1;i<=n;i++) cout<<low[i]<<endl;
    return 0;
}

割边

什么是割边?

和割点差不多,还叫做割桥。

无向联通图中,去掉一条边,图中的连通分量数增加,则这条边,称为桥或者割边,当然也是在无向图。

实现

和割点差不多,只要改一处: \(low_v>num_u\) 就可以了,而且不需要考虑根节点的问题。

割边是和是不是根节点没关系的,原来我们求割点的时候是指点 \(v\) 是不可能不经过父节点 \(u\) 为回到祖先节点(包括父节点),所以顶点 \(u\) 是割点。如果 \(low_v==num_u\) 表示还可以回到父节点,如果顶点 \(v\) 不能回到祖先也没有另外一条回到父亲的路,那么 \(u-v\) 这条边就是割边

\(Tarjan\) 算法还有许多用途,常用的例如求强连通分量,缩点,还有求 \(2-SAT\) 的用途等。

原文地址:https://www.cnblogs.com/lyfoi/p/9612436.html

时间: 2024-11-13 06:01:14

图的割点与割边的相关文章

图的割点与割边(超详细!!!)

·割点 割点概念,应该很好理解: 在一个无向图中,如果删除某个顶点,这个图就不再连通(任意两点之间无法相互到达),那么这个顶点就是这个图的割点. 举个例子: 图中的2号顶点就是割点, 删除2号后,4,5不通,1,6也不通等等 如何求割点? 很容易想到的方法是:依次删除每一个顶点,然后用dfs或者bfs来检查图是否依然连通.如果删除某个顶点后,导致图不再连通,那么刚才删除的顶点就是割点. 这种方法的时间复杂度是O(N(N+M)). 下面寻找复杂度低的方法来解决. 首先从图中任意节点开始dfs遍历上

《啊哈算法》——割点、割边、二分图

这篇文章我们简单的介绍求解图的割点.割边和二分图相关的概念. 割点: 对于含n个点.m条边的连通无向图G,如果去掉顶点vi(并同时去掉与之相连的边),使得G不再连通,那么称vi是一个割点. 通过其定义,我们不难判断某个点是否是割点,但是现在我们面临的问题是,如何给出一个图G,编码让计算机求解割点呢? 首先我们考虑这样一个问题,判定某个点的指标是什么.我们通过人脑来判断其是否是割点,其实是利用非常模糊的视觉效应,即“通过去掉该点观察图是否连通”即可,而如果想要通过计算机来判断,就需要非常量化的判断

Tarjan算法:求解图的割点与桥(割边)

简介: 割边和割点的定义仅限于无向图中.我们可以通过定义以蛮力方式求解出无向图的所有割点和割边,但这样的求解方式效率低.Tarjan提出了一种快速求解的方式,通过一次DFS就求解出图中所有的割点和割边. 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. 割点与桥(割边)的定义 在无向图中才有割边和割点的定义 割点:无向连通图中,去掉一个顶点及和它相邻的所有边,图中的连通分量数增加,则该顶点称为割点. 桥(割边):无向联通图中,去

图的割点算法、图的割边算法

割点算法 • 在一个无向连通图中,如果删除某个顶点后,图不再连通(即任意两点之间不能相互到达),我们称这样的顶点为割点(或者称割顶). 判断一个顶点是不是割点除了从定义,还可以从DFS(深度优先遍历)的角度出发.我们先通过DFS定义两个概念. 假设DFS中我们从顶点U访问到了顶点V(此时顶点V还未被访问过),那么我们称顶点U为顶点V的父顶点,V为U的孩子顶点.在顶点U之前被访问过的顶点,我们就称之为U的祖先顶点. 显然如果顶点U的所有孩子顶点可以不通过父顶点U而访问到U的祖先顶点,那么说明此时去

图的割点、桥与双连通分支

原文地址:图的割点.桥与双连通分支 [点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集合中的顶点数. 类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合.一个图的边连通度的定义为,最小割边集合中的边数. [双连通图.割点与桥] 如果一个无向连通图的点连通度大于1,则称该图是点双连通的(point biconne

【转载】图的割点、桥与双连通分支

[点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集合中的顶点数. 类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合.一个图的边连通度的定义为,最小割边集合中的边数. [双连通图.割点与桥] 如果一个无向连通图的点连通度大于1,则称该图是点双连通的(point biconnected),简称双连通或重连通.一个

【转】图的割点、桥与双连通分支

原文地址:https://www.byvoid.com/blog/biconnect 图的割点.桥与双连通分支 [点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集合中的顶点数. 类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合.一个图的边连通度的定义为,最小割边集合中的边数. [双连通图.割点与桥] 如果一个

『Tarjan算法 无向图的割点与割边』

无向图的割点与割边 定义:给定无相连通图\(G=(V,E)\) 若对于\(x \in V\),从图中删去节点\(x\)以及所有与\(x\)关联的边后,\(G\)分裂为两个或以上不连通的子图,则称\(x\)为\(G\)的割点. 若对于\(e \in E\),从图中删去边\(e\)之后,\(G\)分裂为两个不连通的子图,则称\(e\)为\(G\)的割边. 对于很多图上问题来说,这两个概念是很重要的.我们将探究如何求解无向图的割点与割边. 预备知识 时间戳 图在深度优先遍历的过程中,按照每一个节点第一

图论分支-Tarjan初步-割点和割边

所谓割点(顶)割边,我们引进一个概念 割点:删掉它之后(删掉所有跟它相连的边),图必然会分裂成两个或两个以上的子图. 割边(桥):删掉一条边后,图必然会分裂成两个或两个以上的子图,又称桥. 这样大家就应该能简单理解(怎么可能)割点割边了. 所以我们再来看一个图 这样大家就能明白了吧(明白是明白了,但是要他干嘛(自动忽略))到后面会明白的. 然后怎么求,这是一个问题,直接想法是搜索,枚举每一个点,然后再去检验是否联通,这样的复杂度应该是O(n2),很显然很不优秀,万一数据是1e5以上不就凉凉了吗.