tarjan

Tarjan算法总结

六眼飞鱼酱① 提交于 2019-12-02 06:21:11
Tarjan算法总结 关于学习 《算法竞赛进阶指南》 前言 Tarjan算法能在线性时间内求出无向图的 割点 和 桥 ,进一步可求出无向图的 双连通分量 。并且能在有向图中求出有向图的 强连通分量 、 必经点和必经边 。 只打算给自己复习用,233. Tarjan算法 几个定义: 时间戳:其实就是dfs序 在图的深度优先遍历过程中,按照每个节点第一次被访问的时间顺序, 依次给予 N 个节点 1-N 的整数标记,该标被称为时间戳,记为 dfn[u] 追溯值: 设 subtree(u) 表示搜索中以 x 为根的子树 low[u] 是下述所有节点时间戳的最小值 是 subtree(u) 中的节点 通过 一条 不在搜索树上的边,可以到达 subtree(u) 的节点 关于追溯值的计算: 先令 \(low_u = dfn_u\) v 没有被访问过, \(low[u]=min(low[u], low[v])\) v 被访问过了, \(low[u]=min(low[u], dfn[v])\) Tarjan算法结束, 无向图的割点和桥 割点定义: 给定无向连通图 G=(V,E) 若对于 x ∈ V,从图中删去节点 x 以及所有与 x 关联的边后,G 分裂成两个或两个以上不相连的子图,则称 x 为 G 的割点 若 u 不是搜索树的根节点 (深搜起点),则 x 是割点当且仅当搜索 树上存在 v

图论--割边--Tarjan模板

旧巷老猫 提交于 2019-12-02 05:56:36
#include<iostream> #include<stdio.h> #include<vector> using namespace std; const int maxn=100010; int head[maxn],ver[maxn*2],Next[maxn*2]; int dfn[maxn],low[maxn],sta[maxn]; int n,m,tot,num,root; bool cut[maxn]; void add(int x,int y) { ver[++tot]=y; Next[tot]=head[x]; head[x]=tot; } void tarjan(int x) { dfn[x]=low[x]=++num; int flag=0; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { flag++; if(x!=root||flag>1) cut[x]=1; } } else low[x]=min(low[x],dfn[y]); } } int main() { cin>>n>>m; tot=1; for(int i=1;i<=m;i++) { int x,y;

【模板】tarjan求割点

我只是一个虾纸丫 提交于 2019-12-02 02:02:42
1 int dfn[maxn]; 2 int low[maxn]; 3 bool cut[maxn]; 4 int tot; 5 6 void tarjan(int x) 7 { 8 dfn[x] = low[x] = ++tot; 9 int cntf = 0; 10 for (Re int i = head[x]; i != -1; i = e[i].nxt) 11 { 12 int u = e[i].u; 13 if (!dfn[u]) 14 { 15 tarjan(u); 16 low[x] = min(low[x], low[u]); 17 if (low[u] >= dfn[x]) 18 { 19 cntf++; 20 if (x > 1 || cntf > 1) cut[x] = true; 21 } 22 } 23 else low[x] = min(low[x], dfn[u]); 24 } 25 } View Code 来源: https://www.cnblogs.com/thjkhdf12/p/11724887.html

[题解]luogu_P3469_BLO(理解tarjan/割点

蹲街弑〆低调 提交于 2019-12-01 12:34:45
给定一张无向图,求每个点被封锁之后有多少个有序点对(x,y)(x!=y,1<=x,y<=n)满足x无法到达y 首先不是割点答案为2*(n-1),是割点就要考虑删掉割点会分开哪些连通块 考虑tarjan的过程,核心是对搜索树的处理,如果是割点的话删除掉点x会产生的连通块为x的所有以儿子为根的子树和x子树外的所有部分,每个子树产生的贡献为$size[s1]*(n-size[s1])$,x子树外的贡献为$(size[x])*(n-size[x])$,以及x自己的为$(n-1)$ #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=100009; const int maxm=500009; int n,m,tim,root; struct node{ int v,nxt; }e[maxm<<1]; int head[maxn],cnt=1; inline void add(int u,int v){ e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt; } int dfn[maxn],low[maxn];bool cut[maxn]; ll ans[maxn],sz[maxn]; void tarjan(int x){ dfn[x]=low[x

tarjan好题

坚强是说给别人听的谎言 提交于 2019-12-01 08:56:29
CF652E 洛谷上的 这道题 草从早上调到晚上,最后由帅气的gigo_64同学 调出了我那个无比蒟蒻的垃圾渣渣nmsl草我无语了fuck idiot的问题 首先来分析这道题的做法 当我们看到这种类型的题 我们首先是不会想到边双连通分量的 所以只能多做 然后就熟练了 (说了和没说一样) 但是可以记住的是 边双联通分量可以解决的是缩点之快速求必经边,必经点之类的问题 在这道题中我们可以用边双连通分量缩点,缩完点之后就会是一棵树,然后直接从起点dfs到终点为止 我们可以在处理边双连通分量的时候就处理在该边双连通分量中是否包含魔法石 然后dfs的时候判断经过的边双连通分量或者是边是否包含魔法石 包含输出1 否则输出0 需要注意的一点是,多组数据在clear的时候 如果first数组赋值为-1 需要在遍历的时候 for(int i=first[x];i!=-1;i=nxt[i]) f o r ( i n t i = f i r s t [ x ] ; i ! = − 1 ; i = n x t [ i ] ) emmm 我tm就是因为之前不知道-1是true的 然后判定条件只打了i 然后就凉凉 关键是凉凉成40分?错的数据贼大完全调试不出来 再次感谢gigo_64!! #include <iostream> #include <algorithm> #include <cstring> /

Tarjan算法初步

会有一股神秘感。 提交于 2019-12-01 08:52:50
一、前置知识:    强连通分量:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大(看清是极大,不是最大)强连通子图,称为强连通分量(strongly connected components)。一个点x,若没有点与它强连通,则它自己也是一个强连通分量。 二、算法简述    Tarjan算法是一个主要用于求有向图的强连通分量或无向图的环的算法。(当然也有很多扩展,与其他一些神奇的算法搭配可能会碰撞出奇妙的火花)    (无向图的极大连通子图就不叫强连通分量了,叫连通分量。实际上求无向图的连通分量用bfs就行了(毕竟无向图没有方向,只要能到达,就是连通,也没有强连通这一说)) 三、原理:     想象一个情景:从一个点u出发,一直向下遍历,然后忽得找到一个点,那个点x竟然有条指回点u的边!    那么想必这个点u能够从自身出发再回到自身    想必这个点u和其他向下遍历的该路径上的所有点构成了一个环,    想必这个环上的所有点都是强联通的。    但只是强联通啊,我们需要求的可是强连通分量啊......怎么在退回到这个点的时候,知道所有和这个点u构成强连通分量的点呢?  

「图论」Tarjan

最后都变了- 提交于 2019-12-01 08:23:58
割点 对于一个无向图,如果把一个点删除后这个图的极大连通分量数增加了,那么这个点就是这个图的割点(又称割顶)。 如果尝试删除每个点,并且判断这个图的连通性,那么复杂度会特别的高。所以要介绍一个常用的算法:Tarjan。 首先,上一个图: 很容易的看出割点是 2,而且这个图仅有 2 这一个割点。 首先,按照 dfn 序给他打上时间戳(访问的顺序)。 这些信息被保存在一个叫做 dfn 的数组中。 还需要另外一个数组 low ,用它来存储不经过其入边(你有多个那么就看你遍历到了哪个)能到达的最小的时间戳。 例如 \(2\) 的话是 \(1\) , \(5\) 和 \(6\) 是 \(3\) 。 然后开始 DFS,判断某个点是否是割点的根据是:对于某个顶点 \(x\) ,如果存在至少一个顶点 \(y\) ( \(x\) 的出边),使得 \(low_v>=dfn_u\) ,即不能回到祖先,那么 \(x\) 点为割点。为什么这句话是对的呢?假设当前节点是在下面,他的入边在中间,如果他不经过他的入边访问不到上面的点,那么这个点一定是割点了。 另外,如果搜到了自己(在环中),如果他有两个及以上的出边,那么他一定是割点了,如果只有一个出边,那么把它删掉,不会有任何的影响。比如下面这个图,此处形成了一个环,从 \(1\) 走: 在访问 \(1\) 的出边时候,假设先 dfn 到了 \(2\)

P1726 上白泽慧音(tarjan)

那年仲夏 提交于 2019-12-01 07:25:00
tarjan板子 有一个小地方注意, 第一个最大的强连通分量一定是字典序最小的 ,因为搜索的时候是从小到大的 代码: #include <bits/stdc++.h> #define int long long #define sc(a) scanf("%lld",&a) #define scc(a,b) scanf("%lld %lld",&a,&b) #define sccc(a,b,c) scanf("%lld %lld %lld",&a,&b,&c) #define scs(a) scanf("%s",a) #define schar(a) scanf("%c",&a) #define pr(a) printf("%lld",a) #define fo(i,a,b) for(int i=a;i<b;++i) #define re(i,a,b) for(int i=a;i<=b;++i) #define rfo(i,a,b) for(int i=a;i>b;--i) #define rre(i,a,b) for(int i=a;i>=b;--i) #define prn() printf("\n") #define prs() printf(" ") #define mkp make_pair #define pii pair<int,int> #define pub(a)

Warm up HDU - 4612 树的直径

独自空忆成欢 提交于 2019-12-01 06:57:46
题意:给出n个点和m条边的无向图,存在重边,问加一条边以后,剩下的桥的数量最少为多少。 题解: 你把这个无向图缩点后会得到一个只由桥来连接的图(可以说这个图中的所有边都是桥,相当于一棵树),然后我们只需要找出来这棵树的最大直径(即相距最远的两个点)。然后我们可以把得到的这条链的首尾两端连起来,因为这样减少的桥最多。把所有桥减去这条链上的桥就是答案 找树的直径有两种方法,一种树形dp,一种两次dfs算法。时间复杂度都是O(n) 先说dfs: 实现:随意选取一个点作为我们的起点x,找到以x为起点的和它是最远距离的另一个端点y,然后再以y为起点找到和它是最远距离的另一个端点z,这个y->z就是树的最大直径 本题代码1就是采用的这种解法 再说树形dp: 缺点:无法找到它的直径具体路径 优点:只需一遍遍历 实现: 1 //选取任意结点为根遍历树,设dis[i]:表示结点i为根的子树结点最远距离。 2 //则有: 3 //u为根的子树结点最远距离dis[u]=max(dis[u],dis[u]+W(u-v)) v是u的子节点 4 //最后直径即为根结点的两个最远距离之和 5 int dis[maxn],len=0; 6 void DP(int u,int pre) 7 { 8 dis[u]=0; //初始为0 9 for(int i=head[u];i!=-1;i=e[i].next) 10

12 October

末鹿安然 提交于 2019-12-01 06:12:52
次小生成树 http://poj.org/problem?id=1679 不难得出,次小生成树可以由最小生成树更换一条边得到。 首先构造原图的最小生成树,然后枚举每一条不在最小生成树中的边 (u, v, w),尝试将这条边加入生成树,因为直接加入边会产生环,所以我们需要在加边之前删去最小生成树上 u 到 v 的路径上权值最大的边。在枚举每一条边时我们都会得到一棵生成树,这些生成树中边权和最小的即为要求的次小生成树。 需要在构造最小生成树时将完整的树结构构造出来,并且使用树上倍增算法查询两点间边权值最大的值。 强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强连通,如果任意两点都强连通,那么称这个图为强连通图;一个有向图的极大强连通子图称为强连通分量。 https://oi.men.ci/tarjan-scc-notes/ https://www.cnblogs.com/stxy-ferryman/p/7779347.html 一个强连通分量中的点一定处于搜索树中同一棵子树中。 Tarjan 算法: low[] 表示这个点以及其子孙节点连的所有点中dfn最小的值. s[] 表示当前所有可能能构成是强连通分量的点. col[] 对强连通分量进行染色. v[to[k]]==false 说明无论如何这个点也不能与u构成强连通分量,因为它不能到达u. low[x]=