概念解释

  1. 节点强连通:\(v_i\)与\(v_j\)(\(v_i ≠ v_j\))强连通是指从\(vi\)到\(vj\)和从\(vj\)到\(vi\)都存在路径,即两节点互相可达

  2. 强连通图:在有向图\(G\)中,对于每一对\(v_i、v_j\),\(v_i ≠ v_j\),从\(v_i\)到\(v_j\)和从\(v_j\)到\(v_i\)都存在路径,则称G是强连通图。即任意两个节点强连通的有向图

  3. 强连通分量:有向图中的极大强连通子图称做有向图的强连通分量。对于“极大”一词,我的理解是如果有向图中某部分是强连通的,再加入其它任何节点都将使得该部分变为非强连通,则此部分为原图的一个极大强连通子图

算法作用

可以将有向有环图转化为有向无环图(拓扑图-DAG图)。使得原始图具有拓扑图的种种性质,例如在拓扑图中使用递推可以在线性时间内解决一些最短路(最长路问题)

算法思想

缩点:Tarjan将有环图转化为无环图就是将每一个\(scc\)看作一个点,即所谓的缩点。但缩点并非特意需要代码实现,只是一种概念上的存在,原图在存在形式上仍为一个个独立的点,但我们可以根据不同点的\(scc_id\)值,人为将这些点进行分类,从而将具有相同属性的点划分为一个集合,即实现了缩点操作。

进行一次Tarjan要达成的目标是:1.确定图上任意一点所属的scc编号 2.确定每个scc包含节点的个数

Tarjan求解强连通分量采用了\(DFS\)的搜索顺序,搜索到每一个点时都有一个时间,采用\(dfn[i]\)表示搜索到节点\(i\)时的时间

在一个\(scc\)中,一定有一个\(dfn\)最小的点,即最先被搜素到的点,该\(scc\)中除该点以外的点通过环路可以走到的最小\(dfn\)编号记为\(low[i]\)

Tarjan求scc的过程因为使用栈,存在递归和回溯,所以较难说清它的思考流程,只能是参照代码,理解其中各个数组的含义,学会使用即可。

Tarjan求解强连通分量主要依托的就是以上两个标记数组。我们思考在图的搜索过程中,如何判断出现了环路。在DFS的搜索过程中,每当我们搜索到一点,就会将该点入栈保存现场进行递归搜索其子节点,如果我们在搜索过程中遇到了一个栈中的节点,此时就形成了一个环路。使用栈仅能够判断是否存在环路,无法达成目标,\(dfn\)和\(low\)的作用是标记一个节点被搜索到的顺序和它在scc中实际能走到的点的最小编号,如果搜索节点b的相邻节点时,遇到了栈中的节点a,一定满足\(dfn[a] < dfn[b]\),low[b]也应当由dfn[b]更新为dfn[a],这类节点满足\(dfn != low\)。如果某个节点c的\(dfn == low\),说明从它不能走到编号更小的节点了,即它就是一个scc中编号最小的节点,同属于该scc的节点因为不满足\(dfn == low\),所以都仍处于栈中,此时开始弹栈直到将c弹出,这些弹出的即为同一个scc中的节点,弹出时标记其所属scc编号和累加对应scc节点个数计数器即可

\(DFS\)搜索需要用到栈\(stk\)

\(in_stk[i]\)用来标记点\(i\)当前是否处于栈中

\(Size[i]\)用来记录编号为\(i\)的\(scc\)中点的数量

语言描述起来有些混乱,B站有个讲的不错的视频见下

代码实现

代码中else if (in_stk[j]) low[u] = min(low[u], dfn[j]);,为什么用\(dfn[j]\)而非\(low[j]\)还尚不清楚,在Tarjan's SCC : example showing necessity of lowlink definition and calculation rule?中给出的理由是使用\(low[j]\)就会破坏了\(low\)数组的含义,但我觉得恰恰相反,所以这个问题待定

void tarjan(int u)
{
dfn[u] = low[u] = ++ timestamp;
stk.push(u), in_stk[u] = true; for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[j], low[u]);
}
else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u])
{
do {
int t = stk.top(); stk.pop();
id[t] = scc_cnt;
in_stk[t] = false;
++ Size[scc_cnt];
} while (t != u); // ++ scc_cnt;
// int t = stk.top(); stk.pop();
// id[t] = scc_cnt;
// in_stk[t] = false;
// ++ Size[scc_cnt];
// while (t != u)
// {
// t = stk.top(); stk.pop();
// id[t] = scc_cnt;
// in_stk[t] = false;
// ++ Size[scc_cnt];
// }
}
}

Tarjan强连通分量(scc)的更多相关文章

  1. tarjan 强连通分量

    一.强连通分量定义 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly c ...

  2. 强连通分量SCC 2-SAT

    强连通分量SCC 2-SAT 部分资料来自: 1.https://blog.csdn.net/whereisherofrom/article/details/79417926 2.https://ba ...

  3. Tarjan 强连通分量 及 双联通分量(求割点,割边)

    Tarjan 强连通分量 及 双联通分量(求割点,割边) 众所周知,Tarjan的三大算法分别为 (1)         有向图的强联通分量 (2)         无向图的双联通分量(求割点,桥) ...

  4. tarjan强连通分量模板(pascal)

    友好城市 [问题描述]小 w 生活在美丽的 Z 国. Z 国是一个有 n 个城市的大国, 城市之间有 m 条单向公路(连接城市 i. j 的公路只能从 i 连到 j). 城市 i. j 是友好城市当且 ...

  5. 1051: [HAOI2006]受欢迎的牛 (tarjan强连通分量+缩点)

    题目大意:CodeVs2822的简单版本 传送门 $Tarjan$强连通分量+缩点,若连通块的个数等于一则输出n:若缩点后图中出度为0的点个数为1,输出对应连通块内的点数:否则输出0: 代码中注释部分 ...

  6. 有向图强连通分量SCC(全网最好理解)

    定义: 在有向图中,如果一些顶点中任意两个顶点都能互相到达(间接或直接),那么这些顶点就构成了一个强连通分量,如果一个顶点没有出度,即它不能到达其他任何顶点,那么该顶点自己就是一个强连通分量. 做题的 ...

  7. [poj 2553]The Bottom of a Graph[Tarjan强连通分量]

    题意: 求出度为0的强连通分量. 思路: 缩点 具体有两种实现: 1.遍历所有边, 边的两端点不在同一强连通分量的话, 将出发点所在强连通分量出度+1. #include <cstdio> ...

  8. [poj 1904]King's Quest[Tarjan强连通分量]

    题意:(当时没看懂...) N个王子和N个女孩, 每个王子喜欢若干女孩. 给出每个王子喜欢的女孩编号, 再给出一种王子和女孩的完美匹配. 求每个王子分别可以和那些女孩结婚可以满足最终每个王子都能找到一 ...

  9. 算法模板——Tarjan强连通分量

    功能:输入一个N个点,M条单向边的有向图,求出此图全部的强连通分量 原理:tarjan算法(百度百科传送门),大致思想是时间戳与最近可追溯点 这个玩意不仅仅是求强连通分量那么简单,而且对于一个有环的有 ...

  10. Equivalent Sets HDU - 3836 2011多校I tarjan强连通分量

    题意: 给一些集合 要求证明所有集合是相同的 证明方法是,如果$A∈B$,$B∈A$那么$A=B$成立 每一次证明可以得出一个$X∈Y$ 现在已经证明一些$A∈B$成立 求,最少再证明多少次,就可以完 ...

随机推荐

  1. git和coding的使用

    1.注册 coding ::::::https://coding.net/ 2.个人设置中添加上邮箱账号和密码 3.下载git 4.在coding中新建项目,并对项目初始化---生成分支,会生成url ...

  2. sequelize的创建接口以及模糊查询

    第一步: 在routes里面复制index.js更改为xxx.js(例如arctile.js) res.json()返回的就是json文件 第二步: 在views里app.js引用路由 第三步:查找数 ...

  3. 上分准备 VP Codeforces Round #762 (Div. 3) 4题ABCE

    +00:02 +00:16 +01:08   +02:07 VP 情况  4/8 ABCE ,赛时排名可以到823,什么时候我可以上个青 B 本想写个map的二分的,发现自己不会,写了个普普通通的二分 ...

  4. JavaScript常见事件记录

    JavaScript常见事件记录 onblur: 元素失去焦点 onfocus: 元素获得焦点 onchange: 用户改变域的内容 onclick: 鼠标点击某个对象 ondblclick: 鼠标双 ...

  5. c++标准官网

    gcc官网: https://gcc.gnu.org/ c++参考手册: https://en.cppreference.com/w/cpp c++教程网站: https://www.learncpp ...

  6. SQL Server 还原数据库

    1.备份要还原的数据库 选择要备份的数据库,右键单击,任务--备份. 2.备份完成后,将数据库还原 3.新建一个空的数据库,比如Gsy_TestNew,将备份的数据库还原到这个新的库上 4.右键单击[ ...

  7. 内存、cpu、硬盘使用率测试方法

    平时测试过程中经常需要测试页面展示的系统资源信息是否正确,比如CPU.内存.硬盘等,一般是需要测试服务器的资源情况,服务器一般部署在linux上,今天总结一下测试方法: 1.CPU测试:(使用shel ...

  8. 在gibhub上传本地项目代码(新手入门)

    一.首先注册github账号 地址:https://github.com/ 二.其次下载安装git工具 地址:https://gitforwindows.org/ 直接进入安装,这里就不多做介绍 三. ...

  9. 如何在Windows下使用WebMatrix+IIS开发PHP程序

    最近接收一个新项目,领导要求对客户端的接口采用PHP开发,为了方便,我就采用 Windows7专业版64位 + IIS7.5 + PHP5.5 + WebMatrix 作为开发环境进行开发: 首先下载 ...

  10. 1012.Django中间件以及上下文处理器

    一.中间件 中间件的引入: Django中间件(Middleware)是一个轻量级.底层的"插入"系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出. d ...