首页 > 编程语言 >Tarjan算法和连通性相关(二)

Tarjan算法和连通性相关(二)

时间:2024-08-02 16:16:44浏览次数:11  
标签:Tarjan 连通性 ++ father 割点 算法 dfn low

上一篇博客我们介绍了强连通分量,本文我们继续学习与连通性有关的一些概念

割点

什么是割点?

对于一个无向图,如果把一个点删除后这个图的极大连通分量数增加了,那么这个点就是这个图的割点

我们画个图理解一下:

在这个图中,如果我们把 3 这个点给删除掉,那么这张图就会被拆分成两个部分,极大联通分量数就会增加,所以 3 这个点是割点,可以证明其他点都不是割点

怎么求割点?

与求强连通分量的方法类似,我们可以用Tarjan的思想去求割点

我们取图中的一个点,以它为起点开始做DFS,并维护DFS序,同时与求强连通分量的方法类似,我们也需要维护 low 数组

有了这两个信息,我们就能很快判断一个点是不是割点,因为对于某个顶点 u ,如果存在至少一个儿子顶点 v 使得 \(low[v]\) \(\ge\) $dfn[u] $ ,那么

u 点就是割点,因为删去 u 点,v 点无法到达祖先结点

但是对于搜索的起始点我们需要进行特殊考虑,仔细考虑一下会发现,如果该点只有一个儿子,那么该点就不是割点,如果有两个及以上的儿子,那么该点就是割点(读者可以画图想想这是为什么)

从而,我们利用Tarjan算法求出了割点,代码如下:

void Tarjan(int u, int father){ 
  vis[u]=true;
  low[u]=dfn[u]=++dfncnt;
  int child=0;
  for(auto v:g[u]){
    if(!vis[v]){
      child++;
      Tarjan(v,u);
      low[u]=min(low[u],low[v]);
      if (father!=u&&low[v]>=dfn[u]&&!flag[u]){
        flag[u]=true;
        res++;
      }
    } 
      else if(v!=father){
      low[u]=min(low[u],dfn[v]);
    }
  }
  if (father==u&&child>=2&&!flag[u]){
    flag[u]=true;
    res++;
  }
}

桥(割边)

什么是桥?

对于一个无向图,如果删掉一条边后图中的连通分量数增加了,则称这条边为桥或者割边,如图,红色的那条边就是桥

怎么求桥?

和求割点的思想差不多,只要将更新状态时改成 \(low[v]\) \(\gt\) $dfn[u] $ 就可以了,并且我们不需要考虑根节点的问题(读者也可以画图想想为什么)

代码如下:

void tarjan(int u, int fa) {
  father[u]=fa;
  low[u]=dfn[u]=++dfncnt;
  for (auto v:g[u]) {
    if (!dfn[v]) {
      tarjan(v,u);
      low[u]=min(low[u],low[v]);
      if (low[v]>dfn[u]) {
        isbridge[v]=true;
        ++cnt_bridge;
      }
    } else if(dfn[v]<dfn[u]&&v!=fa){
      low[u]=min(low[u],dfn[v]);
    }
  }
}

标签:Tarjan,连通性,++,father,割点,算法,dfn,low
From: https://www.cnblogs.com/isletfall/p/18339016

相关文章

  • Tarjan算法与连通性相关(一)
    昨天在打牛客多校的时候遇到了一道与连通性有关的图论题,笔者一眼就看出这题考察的知识点是Tarjan算法,但是笔者上次写Tarjan算法还是三年前的事情(太惭愧了qaq),于是笔者和队友在赛时花了一个小时时间学习了Tarjan算法成功通过了此题,故写下这篇博客进一步加深印象,同时也是分享自己对于......
  • 数据结构与算法-二分搜索树节点的查找
    ......
  • 解密编程的八大法宝(三)(附贪心算法、动态规划和字符串匹配算法详解)
    算法题中常见的几大解题方法有以下几种:暴力枚举法(BruteForce):这是最基本的解题方法,直接尝试所有可能的组合或排列来找到答案。这种方法适用于问题规模较小的情况,但在大多数情况下效率不高。贪心算法(GreedyAlgorithm):贪心算法在每一步都选择当前看起来最优的解,希望最终能......
  • Day 31 贪心算法 Part05
    56.合并区间区间这类问题,不是按照左端点排序就是按照右端点排序,在思考思路的时候,就从这两个方向去下手,然后再去想贪心,以及从左侧开始遍历还是右侧开始遍历。classSolution{publicint[][]merge(int[][]intervals){if(intervals.length==1)returninterva......
  • 一文读懂CST电磁仿软件的TLM算法原理和历史背景
    这期我们免公式地介绍一下TLM原理。TLM(TransmissionLineMethod)是传输线矩阵算法,基于Huygens的波传播模型的三维全波电磁算法,注意是fullwave哦!什么是Huygens原理?惠更斯原理能准确计算波的传播。简单讲就是波传播的最前沿(wavefront)上每个点都可以看作是下一时刻的波的点源。......
  • 代码随想录算法训练营第二十一天| 39. 组合总和, 40.组合总和II, 131.分割回文串
    今天是回溯算法学习的第二天,主要的学习内容包括:1.组合问题的重复使用2.组合问题的去重3.分割问题的处理方法。39.组合总和题目链接:39.组合总和-力扣(LeetCode)这个组合问题的特点是,集合内的元素可以重复使用。与前面组合问题的区别在于,在每一次回溯中,不是从i+1的位置开......
  • 数组算法
    数组的算法目录数组的算法搜索方法排序方法排序算法库搜索方法线性搜索(LinearSearch):算法:遍历数组,直到找到目标值或遍历完数组。时间复杂度:O(n)。应用:在未排序的数组中查找元素。publicintlinearSearch(int[]arr,inttarget){for(inti=0;i<arr.......
  • 代码随想录算法训练营第57天 | 并查集理论基础
    并查集理论基础https://www.programmercarl.com/kamacoder/图论并查集理论基础.html107.寻找存在的路径https://kamacoder.com/problempage.php?pid=1179代码随想录https://www.programmercarl.com/kamacoder/0107.寻找存在的路径.html#思路并查集理论基础并查集用于判断......
  • 数组的算法
    数组的算法常见排序算法主要有:冒泡排序,选择排序,计数排序,基数排序,堆排序,桶排序,归并排序,希尔排序,插入排序,快速排序等等。冒泡排序(BubbleSort):两个for循环(外面的遍历数组,数组最后个元素不用遍历,因为要两两比较。里面的进行两两比较)通过重复遍历要排序的数列,比较每对相邻......
  • 解密编程的八大法宝(四)(附二分查找、分治法和图论算法(深度和广度优先搜索、最短路径、最
    算法题中常见的几大解题方法有以下几种::暴力枚举法(BruteForce):这是最基本的解题方法,直接尝试所有可能的组合或排列来找到答案。这种方法适用于问题规模较小的情况,但在大多数情况下效率不高。贪心算法(GreedyAlgorithm):贪心算法在每一步都选择当前看起来最优的解,希望最终能......