本篇文章主要是对tarjan不同用法的讲解 , 其主要目的是复习,当然初学也可以看鸭极有可能看不懂
目录 :1.有向图缩点
2.无向图割点
3.点双连通分量

1.有向图缩点
首先来一道经典题目

给定一个 n个点 m 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
洛谷3387 缩点

这个题的话很明显我们要用tarjan进行缩点,在图中寻找强连通分量对吧,因为这个点如果我们可以走过去的话,那么他所在的连通分量我们也可以都走一遍在回到这里。
当我们缩晚点之后,剩下的就一定是一个有向无环图(DAG)
证明的话可以用反证法 , 如果还有环的话就肯定还有连通 ,但这显然不可能
然后我们在这个图上进行一个dp + 拓扑就可以了(这两个不重要)

所以现在我们就来缩点!!! 先上代码!

#include<bits/stdc++.h>
using namespace std ;
const int M = 100000 + 5 ;
vector<int> g[M] ;
int bccnum[M] ;
int dfn[M] , low[M] ;
int zhi[M] , z[M] , vis[M] , sum[M] , ru[M];
int ans ;
int gx[6666][6666] , dis[6666];
stack<int> s ;
int cloc = 0 ;
int bccnt = 0 ;
inline void tarjan( int u , int fa)
{dfn[u] = low[u] = ++cloc ;  s.push(u) ;  for( int i = 0; i < g[u].size()  ;  i++){register int nxx = g[u][i] ; if( !dfn[nxx]){tarjan(nxx , fa) ; low[u] = min( low[u] , low[nxx] ) ; }else if(!bccnum[nxx])low[u] = min( low[u] , dfn[nxx])  ;}if( low[u] == dfn[u]){++bccnt; while(1){int e = s.top() ;s.pop() ; bccnum[e] = bccnt; sum[bccnt] += z[e] ; if(e==u)break ; }}
}int main(){int n , m ; cin >> n >> m ;for( int i = 1 ; i <= n ; i++){cin >> z[i] ; } for( int i = 0 ; i < m ; i++){register int a , b ; scanf("%d%d" , &a , &b) ;g[a].push_back(b) ;  }for( int i = 1 ; i <= n ; i++){if( !dfn[i] )tarjan(i , i);}topu() ;cout << ans ;return 0 ;
}

我只留下了与tarjan相关的部分

考虑一个强连通分量C , 假设第一个被发现的点是x , 则其他点都是他的后代 , 这样我们可以在一个DFS中把他们找出来。
现在我们先把这x找出来。对于x的子孙们来说 , 他们所能到达的祖先点最多就是x,并且不是自己,所以在这个强连通分量(SCC)中只有x自己是low【x】 = dfn【x】的;
所以说当我们找到这个x的时候 , 我们可以一起把他的子孙们也放到这个SCC
里面 ,这也是我们需要栈的原因;

好了 , 说这么多只要记住 :
在有向图中求SCC的时候是low == dfn , 然后出栈的时候要把这个点也放到这SCC中即可

还有一点 :else if(!bccnum[nx])low[u] = min( low[u] , dfn[nx]) ;
这句话别忘了前面的条件(可能是我太弱了经常忘qwq)就是说可能你指向的这个点是在你之前被访问过了, 但仅仅只是你单方面想过去人家并不喜欢你
所以是不可以更新的!!!

2.无向图割点
这个比较简单,上代码, 里面有注释

inline void tarjan( int u , int fa)
{dfn[u] = low[u] = ++cloc ; int child = 0  ; for( int i = head[u] ; i!=0 ;  i = pre[i].mark){register int nxx = pre[i].xnt ; if( !dfn[nxx]){tarjan(nxx , fa) ; low[u] = min( low[u] , low[nxx] ) ; if( low[nxx] >= dfn[u] && u != fa)//如果说他的孩子们所能到达他的上面,他就不是割点, 不然就是!cut[u] = 1 ; if( u == fa)child++ ; }low[u] = min( low[u] , dfn[nxx]) ; }if( u == fa && child >= 2)//如果说是根节点,只要有两个以上的孩子就可以割了cut[u] = 1 ;
}

3.点双连通分量
首先明确点双连通的定义: 任意两点存在点不重复的路径;
所以点双连通分量的极大子图为点双连通分量(BCC)
然后这个是在无向图中废话,但是我们是把边推进栈中 ,因为不同BCC可能有重复的点 !!!
然后这个看看代码应该可以懂
提供样例:1-2 2-3 1-3 3-4 4-5 5-6 这个图中两个BCC为{1 , 2 ,3 } 和{3 , 4, 5} ;

vector<int> bcc[maxn] // 这里用vector存的是一个BCC中有哪些点
//bccnum存的是这个点位于哪一个BCC
//但是不是所有点都可以 , 比如样例中的3 因为它同时存在于两个BCC中
if(low[v] >= dfn[u]){bcccnt++ ;for( ; ; ){edge x = s.top() ; s.pop() ; if(bccnum[x.u] != bcccnt){bcc[bcccnt].push_back(x.u)bccnum[x.u] = bcccnt ; }if(bccnum[x.v] != bcccnt) {bcc[bcccnt].push_back(x.v)bccnum[x.v] = bcccnt ;}if(x.u == u && x.v == v) break ; }
}

这个点双连通代码来自lrj的蓝书 请读者自行思考
主要是因为感觉不常用到, 但还是要知道鸭!!!

总结

有向图缩点 :low[u]==dfn[u]
无向图割点:dfn[u]<=low[v]
点双连通分量:同上 , 但是入栈的是边

感谢观看,码字不易 ,点个赞吧QWQ

完结撒花

有问题请评论谢谢鸭

图论---tarjan相关推荐

  1. 0x66.图论 - Tarjan算法与无向图连通性

    目录 一.无向图的割点与桥 割点 桥/割边 时间戳 搜索树 追溯值 二.割边判定法则 三.割点判定法则 1.luogu P3388 [模板]割点(割顶) 2.luogu P3469 [POI2008] ...

  2. 图论——Tarjan 初步 DFS序+时间戳+欧拉序

    一.什么是DFS序: DFS序是按照先序遍历,先遍历根节点然后依次遍历左子树,右子树的过程,每次遇到新的节点就把新访问节点加到序列中,代码如下: int DFSrk[100000]; int cnt= ...

  3. 图论--tarjan求lca

    这是一种离线算法,但是时间超级快,是O(n+m). 主要是dfs实现这个过程. 下面详细介绍一下Tarjan算法的基本思路: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记 ...

  4. P2002 消息扩散(图论 Tarjan缩点)

    原题链接:消息扩散 - 洛谷  写在前面:缩点是对于有向图的 思路:想一下就能发现,其实就是要找到有多少个入度为0的点,以它们为消息源得到的结果是最小的.但是有两个问题:有环.重边.有环->缩点 ...

  5. 各种模板(数据结构图论)

    文章目录 数据结构 LCT 线段树 线段树分治 树状数组 图论 Tarjan 静态仙人掌 最小生成树 最短路-Floyd 最短路-Dijkstra 最短路-Bellman-Ford 最短路-SPFA ...

  6. 算法竞赛知识合集 目录(博客中转站)

    目录 0x00. 基本算法 0x01. 基本算法 - 位运算 0x02. 基本算法 - 递推与递归 0x03. 基本算法 - 前缀和与差分 0x04.基本算法 - 二分和三分 0x05.基本算法 - ...

  7. OI模板のpoke流[大型考试复习必备/kl]

    数论 快速乘: ll qmul(ll x,ll y,ll mod) {ll ans=0;while(y){if(y&1) (ans+=x)%=mod;y>>=1;(x+=x)%=m ...

  8. NOIP模拟测试13「矩阵游戏·跳房子·优美序列」

    矩阵游戏 考试时思路一度和正解一样,考试到最后还是打了80分思路,结果80分打炸了只得了40分暴力分 题解 算出来第一列的总值,每次通过加每两列之间的差值得出下一列的总值 算第一列我们只需要让当前点* ...

  9. 算法提高课-图论-有向图的强连通分量-AcWing 367. 学校网络:强连通分量、tarjan算法

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 第一问:通过tarjan算法求出强连通分量并且缩点后,统计入度为0的点的个数p即可. 第二问,至少加几条边才能使图变成强连通分量?这 ...

最新文章

  1. Nginx 提示host not found in upstream 错误解决方法
  2. 用JS读取XML文件
  3. VR原理讲解及开发入门
  4. Windows和Virtualbox虚拟机之间拷贝文件
  5. ORA-01502: 索引'P_ABCD.PK_WEB_BASE'或这类索引的分区处于不可用状态
  6. html5手机网站照片查看器,PhotoSwipe
  7. MATLAB GPU编程基础
  8. 云计算实战系列十(文件查找及包管理)
  9. linux中node跨服务执行文件,linux部署node.js服务并启动服务
  10. android view绘制速度,关于android ui的优化 view 的绘制速度
  11. 送书《数据库系统概念》,送课,SQL必备!!
  12. kodexplor类似php,Windows 下搭建 PHP + Nginx + KODExplorer
  13. 网吧服务器多长时间维护,网吧服务器常用设置维护工具
  14. JEESZ 模块开发文档
  15. selenium+Java切换窗口句柄
  16. HSV颜色分割,RGB与HSV颜色空间的关系
  17. Android OpenGl ES使用原理总结与代码示例
  18. 正则匹配所有字符(包括换行)
  19. WIN10+CUDA 10.2+CUDNN v8.0安装配置
  20. 谈谈游戏AI的一些基础知识

热门文章

  1. ESP8266 对接RFID RC522 设备读取门禁卡
  2. python基于模糊推理的智能家居安防系统设计
  3. ElasticSearch入门:使用ES来实现模糊查询功能
  4. 2017毕设论文小结
  5. 最新华为鸿蒙系统升级名单,鸿蒙系统首批升级机型名单_华为鸿蒙系统升级机型名单时间表...
  6. 墙面投影面积的计算方法
  7. HTML学习之四CSS盒子
  8. python中quit函数用法_quit(code=None)函数和exit(code=None)函数的使用举例
  9. Java实现将本地.html文件以.docx文件格式导出并添加水印
  10. Linux 中 which、whereis、locate、find的区别