tarjan算法求强联通分量

昨天学到了一个新的算法tarjan算法,感觉最近都没有怎么学习了。。。(最近有个感悟啊,就是学习一定的通过实践来进步的。 现在才明白为什么高中的时候老师强调一定要刷题,当然刷完题目之后的总结也非常地重要!

这个tarjan算法用来求强联通分量,在网上看了几篇blog,然后做了一个题目,感觉这个算法很nice啊。。。

如果没有学这个算法, 我肯定会想直接dfs吧orz... dfs看看是不是每个点能到达连通分量的其他点,好像这样非常麻烦啊,还要记录这个点从哪里来的。。。这样一想,好像直接dfs我做不来啊。。。(orz 太菜了。

那就看看tarjan打野的算法吧。。。

这个算法用到了两个数组(low 和 dfn数组)和 数据结构栈 还有一个标记数组stk[]用来记录一个点是否在栈中,个人认为这两个数组才是这个算法的关键之处! low用来记录当前连通分量的子树的下标(子树的下标最小,因为我们也是从下标小的点开始dfs 的),dfn用来记录当前这个点被访问的时间,所以在后面的操作中,我们不要去修改dfn的值(因为一个点的被访问时间的确定的啊),我们要修改的是low的值。

算法的步骤大概如下:

step1:初始化low,dfn, low[u]=dfn[u]=++time;

step2:将u压栈并且标记为在栈中 stk[u]=1;

step3:一个for循环找与u相邻的点v,这里分两个情况 (这里就是dfs的模拟)

  1)如果v未被访问,那么就去dfs(v),如果存在环的话,会导致 low[v]被更新为子树的根的dfn值,所以dfs结束的时候,我们更新一下low[u]=min(low[v], low[u]),有人会问了,如果没有环呢?没有环就更好办了,没有环的话,v是从u搜索过来的 low[v]的初始值大于low[v]的初始值,所以low[u]=min(low[u], low[v])并不变。

  2)如果v已经被访问过,就看看它在不在当前的栈中,如果在,说明v和u同属于一棵子树(那我们更新一下low[v]=min(dfn[u], low[v]) )

step4:如果一个点的邻边都已经搜索完了,那就从step3跳出来了,这个时候判断一个这个点u的low[u]和dfn[u]是否相等,相等的话说明它是一个强连通分量的根,可以证明一下:如果它不是根的话,那么u的low在step3就已经被更新成了根的dfn,而根的dfn值肯定比low[u]更小的,所以low[u]肯定被更新了且不等于dfn[u]。当low[u]和dfn[u]相等的时候,我们就把压在栈中的同属于一个连通分量的点全部pop,并设stk[u]=0;(表示当前元素已经不在栈中了)。。。因为我们是从节点下标小的点开始dfs的,所以一个联通分量的根节点肯定是节点小下标的点,这样就可以保证pop操作能成功将所有联通分量的点pop出来!

时间: 2024-10-11 08:15:42

tarjan算法求强联通分量的相关文章

Tarjan 算法求强联通分量

转载自:http://blog.csdn.net/xinghongduo/article/details/6195337 还是没懂Tarjan算法的原理.但是感觉.讲的很有道理. 说到以Tarjan命名的算法,我们经常提到的有3个,其中就包括本文所介绍的求强连通分量的Tarjan算法.而提出此算法的普林斯顿大学的Robert E Tarjan教授也是1986年的图灵奖获得者. 首先明确几个概念. 强连通图.在一个强连通图中,任意两个点都通过一定路径互相连通.比如图一是一个强连通图,而图二不是.因

[ACM] HDU 1269 迷宫城堡(Tarjan算法求强联通分量)

迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 8099    Accepted Submission(s): 3623 Problem Description 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A

Tarjian算法求强联通分量

如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. Tarjan算法是用来求有向图的强连通分量的.求有向图的强连通分量的Tarjan算法是以其发明者Robert Tarjan命名的

tarjan算法 求所有联通分量

摘自:https://blog.csdn.net/qq_34374664/article/details/77488976  (感谢) tarjan算法,之所以用DFS就是因为它将每一个强连通分量作为搜索树上的一个子树.而这个图,就是一个完整的搜索树.为了使这颗搜索树在遇到强连通分量的节点的时候能顺利进行.每个点都有两个参数.1,DFN[]作为这个点搜索的次序编号(时间戳),简单来说就是 第几个被搜索到的.%每个点的时间戳都不一样%.2,LOW[]作为每个点在这颗树中的,最小的子树的根,每次保证

Tarjan算法求有向图强连通分量并缩点

// Tarjan算法求有向图强连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; const int N = 100010, M = 1000010; // int ver[M], Next[M], head[N],

USACO06JAN The Cow Prom /// tarjan求强联通分量 oj24219

题目大意: n个点 m条边的图 求大小大于1的强联通分量的个数 https://www.cnblogs.com/stxy-ferryman/p/7779347.html tarjan求完强联通分量并染色后 计算一下每种颜色的个数 就是每个强联通块的大小 #include <stdio.h> #include <cstring> #include <algorithm> #include <stack> using namespace std; const i

hihoCoder#1185 : 连通性&#183;三 tarjan求强联通分量 缩点 dfs/拓扑排序求路径和最大值

题目链接: http://hihocoder.com/problemset/problem/1185# 题意: n个点,每个点有一个权值,m条有向边,从1出发,每走到一个点, 就吃掉这个点的草,当没有可以到达的草场或是能够到达的草场都已经被吃光了之后就要返回到1了.求最多可以吃掉多少草. 思路: 提示里面讲的挺好的 如果草场是一个强连通图,那么我们只要走到任意一点,就可以把其他所有的草场都走一遍,并且可以选择任意一个点作为终点.所以把强联通块缩成一个点 因为一个强连通块会被缩成一个点,那么我们可

tarjan求强联通分量 模板

1 void tarjan(int u) 2 { 3 dfn[u]=low[u]=++dfs_clock; 4 stack_push(u); 5 6 for (int c=head[u];c;c=nxt[c]) 7 { 8 int v=to[c]; 9 if (!dfn[v]) 10 { 11 tarjan(v); 12 low[u]=min(low[u],low[v]); 13 } 14 else if (!scc[v]) 15 low[u]=min(low[u],dfn[v]); 16 }

HDU 1269 迷宫城堡 (强联通分量,Tarjan算法)

Problem Description: 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间.Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i. Input: 输入包含多组数据