博客
关于我
Tarjan算法(模板)
阅读量:279 次
发布时间:2019-03-03

本文共 1250 字,大约阅读时间需要 4 分钟。

算法思想: 首先要明确强连通图的概念,一个有向图中,任意两个点互相可以到达;什么是强连通分量?有向图的极大连通子图叫强连通分量。

给一个有向图,我们用Tarjan算法把这个图的子图(在这个子图内,任意两个点可以相互到达,极大的子图)缩成一个点,相当于化简;
怎样去做:从一个点开始遍历它能走到的下一个点(dfn记录时间戳,low记录能回到的最早的时间戳),每遍历到一个点,判断这个点如果没有走过(dfn值为零),继续深搜,如果走过了并且在栈里面说明可以形成一个环(那就可以缩成一个点,更新当前点low的值,回到更早的时间戳),搜完它可以到达所有的点以后回溯,更新low;直到回到 low[u]==dfn[u](环的“根节点"),出栈这个点上面的所有的点(包括这个点本身,他们可以缩成一个点).继续回溯.
特别注意:

else if(instack[v])/*走过并且形成一个环??????*/            low[u]=min(low[u],dfn[v]);/*更新最小值low,合并集合*/            /*不能写成low[u]=min(low[v],low[u])*/

当计算有多少个强连通分量的时候,写成那个没关系,但是如果是求割点,两个语句求出来的low值不一样,值会偏小,割点判断错误(因为判断条件是if(low[v]>=dfn[u]))。

扩展:
计算出入度,问加多少条边可以变成一个整个连通分量:
在这里首先缩点,用一个color[ ]数组,将同一集合的点标记成某个序号(出栈的时候就是同一集合),最后遍历输入的边,用两个数组标记每一个集合的出度入度情况,得出入度和出度分别有几个集合为零,输出最大值。注意:调用tarjan函数的时候,用for循环,因为图可能不连通!还有当它本来就是一个连通分量的时候,特判一下。
例题:POJ 1236
Network of Schools

#include
#include
#include
#include
#include
#include
using namespace std;#define N 1010vector
edge[N];vector
belong[N];stack
s;int low[N];/*所属的强连通数组*/int dfn[N];/*访问的顺序*/bool instack[N];/*是否在栈内*/int n,m,u,v,cnt,cntb;/*n个顶点,m条边*/void Tarjan(int u)/*当前处于的节点*/{ ++cnt;/*计算访问到第几个点(时间戳)*/ dfn[u]=low[u]=cnt;/*访问的顺序(时间戳),low数组记录这个点所能回到的最早的时间戳*/ s.push(u); instack[u]=true; for(int i=0;i

转载地址:http://imsl.baihongyu.com/

你可能感兴趣的文章
[选拔赛1]花园(矩阵快速幂),JM的月亮神树(最短路),保护出题人(斜率优化)
查看>>
76. 最小覆盖子串
查看>>
牛客——链表指定区间翻转
查看>>
DLA:一种深度网络特征融合方法
查看>>
890. 查找和替换模式
查看>>
598. 范围求和 II
查看>>
leetcode练习2(链表表示两数之和)
查看>>
leetcode114(二叉树展开为链表)
查看>>
leetcode226(翻转二叉树:二叉树的遍历)
查看>>
leetcode47(全排列II:回溯+哈希去重)
查看>>
java —— this 关键字
查看>>
java —— static 关键字
查看>>
POJ 1797 最短路变形所有路径最小边的最大值
查看>>
Emacs:Eldoc 全局化了 | Linux 中国
查看>>
Richard Stallman 被迫辞去 FSF 主席的职务 | Linux 中国
查看>>
Firefox 69 已可在 Fedora 中获取 | Linux 中国
查看>>
Linux 中国徽标征集活动结果 | Linux 中国
查看>>
NVIDIA 的云游戏服务 GeForce NOW 无耻地忽略了Linux | Linux 中国
查看>>
黑吃黑——黑客组织通过黑客工具攻击其他黑客 | 每日安全资讯
查看>>
在 Python 调试过程中设置不中断的断点 | Linux 中国
查看>>