scc

tarjan有向图的强连通分量

旧城冷巷雨未停 提交于 2019-12-06 08:35:40
  有向图强 连通分量 :在 有向图 G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点 强连通 (strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个 强连通图 。有向图的极大强连通子图,称为强连通分量(strongly connected components)。   通过对强连通分量的缩点,可以将任意一个有向图变成一个有向无环图(DAG)。 我们将边分为四类:1.树枝边(x是y的父亲结点)2.前向边(x是y的祖先结点)3.后向边(x是y的子孙结点)4.横叉边(连向其他分支的并且已经搜过的边) 可以看出,树枝边是前向边的特殊情况。 如何判断x所在的位置在哪个强连通分量中? 情况1: 存在一条边后向边,指向祖宗结点。 情况2: 先由该点通过横叉边走到另一个分支,再由分支走到该点的某个祖宗结点上。 这里用tarjan算法求强连通分量。我们引入一个时间戳的概念,如上图,用dfs对其进行编号。 对每个点定义两个时间戳dfn[u]和low[u]表示从u开始走,所能遍历到的最小时间戳是什么。如果u是其所在的强联通分量重的最高点,等价于 dfn[u] == low[u] 。 可以证明,通过dfs搜图,能得到该图拓扑图的逆序,tarjan就是按照dfs的顺序搜索,所以

Tarjan

拥有回忆 提交于 2019-12-05 15:11:29
有向图的强连通分量:两个点如果能够相互到达,那么称他们相互强连通。若一个有向图的所有点对都是相互强连通的,那么称之为强连通图。一个有向图的极大强连通子图称为该图的强连通分量。 无向图的割点/边:去掉该点/边之后无向图的连通性发生改变的点/边称为割点/边。 无向图的点/边双连通分量:若一个无向图不存在割点/边,则称作点/边双连通图。一个无向图的极大点/边双连通子图称为该图的点/双连通分量。 强连通分量记为scc,点双连通分量记为v-dcc,边双连通分量记为e-dcc,双连通分量统一记为dcc。 缩点 遍历到时把点加入栈。 然后如果回溯到某个点时 \(low_u=dfn_u\) ,那么我们栈上面的一部分(弹完 \(u\) 为止)就是一个scc。 注意Tarjan求出来的scc编号恰好是拓扑序反序。 我们可以把每个scc缩成一个点,那么我们可以得到一个DAG。 然后我们就可以在这个DAG上面根据拓扑序DP了。 割点 如果一个点 \(u\) 存在一个出点 \(v\) ,满足 \(low_v\ge dfn_u\) ,那么 \(u\) 就是该图的一个割点。 如果是dfs的根节点,那么需要存在两个触点满足上述条件才是一个割点。 而两个v-dcc之间由割点连接,而且有且仅有一个割点。 所以一个割点可能属于多个v-dcc。 v-dcc的维护需要圆方树,这里就不做研究了。 割边(桥) 如果一条边 \(

P5025 [SNOI2017]炸弹

我只是一个虾纸丫 提交于 2019-12-03 17:09:54
原题链接 https://www.luogu.org/problem/P5025 闲话时刻: 第一道 AC 的黑题,虽然众人皆说水。。。 其实思路不是很难,代码也不是很难打,是一些我们已经学过的东西凝合在一起,只要基础扎实的话,做出这道题目来说也就很简单了(不包括我); 题目大意: 有 n 个点,每个点可影响到它左右各 R [ i ] 范围内的点,并且影响到的点会产生连锁反应,求每个点能影响到多少个点; 题解: 一个很简单的思路: 向每个炸弹爆炸范围内的其他炸弹连一条 有向边 < u , v >,表示 u 能炸到 v,最后我们从每个点开始跑 dfs,看看能到达多少个点就好了; 但是。。。 这样连边的话,最劣情况下会连 n 2 条边,看一眼 n 的范围: N ≤ 5 0 0 0 0 0,嗯,显然不行 ~o(* ̄▽ ̄*)o; 考虑建边优化: 不难想到一个炸弹的爆炸范围是一个长度为 2 * R [ i ] 的区间,这个区间内的所有炸弹都会被引爆,因此被引爆的炸弹也是一个连续的区间; 区间操作?你想到了什么? 线段树优化建边 假如说一个炸弹 x 能炸到第 2~6 个炸弹,考虑怎么建边: 一般操作: 线段树优化建边: 建了 5 条边?看我的! 我们发现,这种建边方式只需要建 ⌈ log 2 5 ⌉ = 3 条边; 看了上面的图,应该对 线段树优化建边 有了一个初步的认识了:

P5022 旅行

偶尔善良 提交于 2019-12-03 11:39:27
原题链接 https://www.luogu.org/problem/P5022 本着快csp了,做点往年的NOIp的题试试水来着,没想到 水这么深 难度还挺大的,耗了我一天的时间(可能是我太菜了) 题目大意: 给你 n 个点和 m 条边,问如何遍历每个结点才能使最后的字典序最小,注意只有遍历完一棵字树的所有结点后才能回溯到他的父亲结点; 前 60 pts: 作为 NOIp2018 day2T1 来说,部分分确实给的挺足的,这 60 pts 就是哦; 看到 m = n-1 说明这是一棵树,考虑用搜索: 既然要保证是字典序最小,那么我们第一个点一定要选 1 了,考虑接下来只需要从他的儿子里 按照编号从小到大遍历 就好了,注意要遍历完一棵子树才能回溯上去; 后 40 pts: m = n ?嗯,基环树! 所谓基环树,就是说在一个图里,有 n 个结点和 n 条边,那么这个图内有且仅有一个环; 我们仍然可以按照前 60 pts 的做法上去想: 按理来说我们遍历完 n 个结点只需要走 n-1 条边就好了啊,所以一定有一条边是多余的,也就是说我们根本遍历不到它,那么我们可以枚举每一条边,暂时把它删掉,然后和刚才的做法一样跑一遍 dfs,这样能求得一个字典序,我们取所有字典序中最小的一个就是答案了; 优化 显然如果我们像上述做法那样暴力的话,是会有几个点 TLE 的

缩点

独自空忆成欢 提交于 2019-12-03 06:31:38
老师讲图论-缩点-复习 我想 我没学过 缩点啊 \(OTL\) 先讲 割点 定义 在无向连通图中,如果将其中一个点以及所有连接该点的边去掉,图就不再连通,那么这个点就叫做割点 P3388 【模板】割点(割顶) 主要思想 观察 \(DFS\) 搜索树,我们可以发现有两类节点可以成为割点: 对根节点 \(u\) ,若其有两棵或两棵以上的子树,则该根结点u为割点; 对非叶子节点 \(u\) (非根节点),若其中的某棵子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与该棵子树的节点不再连通;则节点u为割点。 我们用 \(dfn[u]\) 记录节点u在DFS过程中被遍历到的次序号, \(low[u]\) 记录节点 \(u\) 或 \(u\) 的子树通过非父子边追溯到最早的祖先节点(即 \(DFS\) 次序号最小),那么 \(low[u]\) 的计算过程如下: #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define reg register int #define isdigit(x) ('0' <= (x)&&(x) <= '9') template<typename T> inline

Visual Studio 2015 with Update 2 - &#039;The Scc Display Information package did not load correctly&#039;

匿名 (未验证) 提交于 2019-12-03 02:45:02
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试): 问题: Loading a project in Visual Studio 2015 with Update 2 (either automatically when VS start or manual load), I receive an error saying: 'The Scc Display Information package did not load correctly'. The ActivityLog has: <entry> <record>541</record> <time>2016/04/01 13:43:26.048</time> <type>Error</type> <source>VisualStudio</source> <description>SetSite failed for package [Scc Display Information][An item with the same key has already been added.]:{ at Microsoft.VisualStudio.Services.VsTask.InternalGetResult(Boolean ignoreUIThreadCheck) at

[Tarjan系列] Tarjan算法与有向图的SCC

£可爱£侵袭症+ 提交于 2019-12-02 23:49:23
前面的文章介绍了如何用Tarjan算法计算无向图中的e-DCC和v-DCC以及如何缩点。 本篇文章资料参考:李煜东《算法竞赛进阶指南》 这一篇我们讲如何用Tarjan算法求有向图的SCC( 强连通分量 )已经如何缩点。 给定一张有向图,若对于图中任意两个节点x和y, 既有x到y的路径,又有y到x的路径,则该有向图是一张“强连通图”。 有向图的极大连通子图被称为“强连通分量”,即SCC。 一个环一定是强连通图。如果既有x到y的路径,又有y到x的路径,那么x和y就一定在一个环中。 这就是Tarjan算法的原理:对于每个点x,找到与它一起能构成环的所有点。 下面介绍有向图中的三种边(x,y): 1. 树枝边:搜索树中x是y的父节点 2. 前向边:搜索树中x是y的祖先节点 3. 后向边:搜索树中y是x的祖先节点 4. 横叉边:除了以上三种情况外的边,满足dfn[y]<dfn[x] 这里只给出简单定义,不再赘述。 我们可以发现,用Tarjan算法求SCC时,后向边(x,y)可以和搜索树上从y到x的路径构成一个环。 除后向边外,通过横叉边也可能找到一条从y出发能回到x的祖先节点的路径。 那么为了找到通过横叉边和后向边构成的环,Tarjan算法在dfs的过程中维护一个栈,当访问到节点x时,栈中需要保存以下两类节点: 1. 搜索树上x的祖先节点,记为集合anc(x)。设y∈anc(x)

[NOI2017]游戏与2-sat方案输出

馋奶兔 提交于 2019-12-02 03:24:45
本文介绍了2-SAT输出一种方案的方法与证明,以及一种 $ O(nm) $ 复杂度输出最小字典序的方法. 2-SAT输出一种方案 先判定是否有解,缩点后得到一张DAG.对于命题组 $ (i,i') $ ,我们选择 $ i $ 和 $ i' $ 中拓朴序靠后的一个即可. 同时由于Tarjan缩点时本来就是拓朴序倒序缩点的,只需要选择 $ i $ 和 $ i' $ 中所属强连通分量中编号小的那个即可. 下面证明这种方案的正确性.我们使用反证法. 假如这样的做法不对,也就是说,会存在一条边 $ (u,v) $ ,使得命题 $ u $ 为 $ true $ 而命题 $ v $ 为 $ false $ . 因为命题 $ u $ 为 $ true $ ,我们得到命题 $ u' $ 的拓扑序在命题 $ u $ 之前.因为存在边 $ (u,v) $ ,我们得到命题 $ u $ 的拓扑序在命题 $ v $ 之前.而2-SAT问题具有对称性,即逆否命题之间真假性相同.如果选 $ u $ 则必须选 $ v $ ,反过来如果不选 $ v $ 则一定不能选 $ u $ ,所以就存在边 $ (v',u') $ ,从而拓扑序的顺序应该是 $ (v',u',u,v) $ , 那么 $ v $ 的拓扑序在 $ v' $ 之后,这与 $ v $ 为 $ false $ 矛盾. 2-SAT 字典序最小方案 从一号点开始

LuoguP2002 消息扩散 tarjan求scc

强颜欢笑 提交于 2019-12-01 06:12:05
模板,注意有个地方打错好多次了: for(int j = 0;j < scc[i].size();j++)——是j++不是i++!!! 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 7 const int Maxn = 100010; 8 9 int ind[Maxn],dfn[Maxn],low[Maxn],stack[Maxn],ins[Maxn],inscc[Maxn]; 10 vector<int> scc[Maxn],g[Maxn]; 11 int cntscc,cntv,n,m,top; 12 13 void tarjan(int x){ 14 dfn[x] = low[x] = ++cntv; 15 ins[x] = 1,stack[++top] = x; 16 for(int i = 0;i < g[x].size();i++){ 17 int u = g[x][i]; 18 if(!dfn[u])tarjan(u),low[x] = min(low[x],low[u]); 19 else if(ins[u])low[x] = min(low[x],dfn[u]); 20 } 21 if(dfn[x] ==

[CF1142E] Pink Floyd

假装没事ソ 提交于 2019-11-28 08:28:11
传送门 题意:一个 \(n\) 个点的竞赛图,给出 \(m\) 条红色的边,其方向确定,其余边均为绿色,方向未知。你可以询问不超过 \(2n\) 次,每次询问一条绿色边的方向。要求找到一个点 \(x\) ,使得 \(x\) 出发到任意一个点都有至少一条同色路径。 \(n ,m\leq 10^5\) 。可能会在交互过程中动态构造图。 考虑没有红色的边时怎么做。显然在询问过程中会形成若干棵绿色的外向树,每次询问两棵外向树的树根,将它们合并起来即可。最后剩余的点即为答案。 回到原题,发现由于红色边的存在导致有些边无法通过询问定向,但是红色边本身可以作为连通的方式。 将红色连通块缩点,发现此时任何没有红色入度的点均与上文中的绿色外向树等价,即,这些点满足可以任意询问两两之间的边,且这样的点只剩一个时即为答案。 另一个值得注意的点是,合并时被删除的点可能会有若干红色出边,此时需遍历这些边,并将新的满足条件的点加入待处理点集中。 Code: #include <queue> #include <cstdio> #include <cctype> #include <cassert> #include <cstring> #include <iostream> #include <algorithm> #define R register #define ll long long using