tarjan

schlnet Tarjan强连通分量

不想你离开。 提交于 2019-11-26 15:52:04
schlnet ★★★ 输入文件:schlnet.in 输出文件:schlnet.out 简单对 比 时间限制:1 s 内存限制:128 MB 描述 一些学校连入一个电脑网络。那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作 “ 接受学校 ” )。注意如果 B 在 A 学校的分发列表中,那么 A 不必也在 B 学校的列表中。 你要写一个程序计算,根据协议,为了让网络中所有的学校都用上新软件,必须接受新软件副本的最少学校数目(子任务 A )。更进一步,我们想要确定通过给任意一个学校发送新软件,这个软件就会分发到网络中的所有学校。为了完成这个任务,我们可能必须扩展接收学校列表,使其加入新成员。计算最少需要增加几个扩展,使得不论我们给哪个学校发送新软件,它都会到达其余所有的学校(子任务 B )。一个扩展就是在一个学校的接收学校列表中引入一个新成员。 INPUT FORMAT (file schlnet.in) 输入文件的第一行包括一个整数 N :网络中的学校数目( 2 <= N <= 100 )。学校用前 N 个正整数标识。接下来 N 行中每行都表示一个接收学校列表(分发列表)。第 i+1 行包括学校 i 的接收学校的标识符。每个列表用 0 结束。空列表只用一个 0 表示。 OUTPUT FORMAT(file schlnet.out) 你的程序应该在输出文件中输出两行

Tarjan——强连通分量

旧街凉风 提交于 2019-11-26 12:27:57
是的你没有看错,又是Tarjan(说过他发明了很多算法),那么什么是Tarjan 首先看看度娘的解释: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。 是不是没有看懂,我也是 首先了解几个概念:强连通,强连通图,强连通分量 强连通:在一个有向图G中,两个点a,b,a可以走到b,b可以走到a,我们就说(a,b)强连通 强连通图:在一个有向图G中,任意两个点都是强连通 强连通分量:在一个有向图G中,有一个子图,它任意两个点都是强连通,我们就说这个子图为强连通分量 ,特别的,一个点也是一个强连通分量 如图所示: 显然可得:1,2,3,5 构成了一个强连通分量(一个点也是) 下面进入正题,厉害的Tarjan发明的厉害的Tarjan 首先引进一个概念(以前应该都学过),时间戳,用数组dfn表示(应该不用讲吧),也就是搜索这个图的顺序(最后还是讲了) 每个节点的时间戳不同 再是一个low数组,low[x]表示以x为根的子树中,每个节点中连接的点的时间戳的最小值(可能有点难懂,但这个非常重要

Tarjan学习笔记

江枫思渺然 提交于 2019-11-26 10:21:39
集训太棒了 首先,强连通分量的定义: 有向图内,一个强连通分量内任一点之间豆村咋至少一条路径。 直观一点? 一个点集,在有向图上它们构成了一个环(个人理解但的确是这样) 一些定义: Dfn(u)是节点u的时间戳,表示点u是第几个被访问的节点。 Low(u)是u或u的子树能够追溯到的最早的栈中节点的时间戳。 当Dfn(u)=Low(u)时,以u为根的搜索子树上所有节点(从栈顶到u的所有节点)是一个强连通分量。 Low数组的计算方法: 如果x→y是正向边(连接到不在栈中节点的边), y是x的子树,所以y最早能去哪x最早就能去哪 那么 low[x]=min(low[x],low[y]) 如果x→y是反向边(连接到已在栈中节点的边),这时候我们发现构成环了 那么 low[x]=min(low[x],dfn[y]) 如果x→y是交叉边(连接到已经出栈的节点的边), 什么也不干 不理解? code: int n,m; #define maxn 10009 vector<int> son[maxn]; int tim,size[maxn],belong[maxn],scc_cnt,cnt; bool bein[maxn]; int st[maxn]; int dfn[maxn],low[maxn]; void Tarjan(int rt) { dfn[rt]=low[rt]=++tim; st[

HDU6165 Tarjan缩点+拓扑排序

左心房为你撑大大i 提交于 2019-11-26 09:57:58
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6165 题意:给出一个有向无自环,无重边的图,判断任意两点是否能到达(只要一个能抵达另一个即可) 这是做的第一道拓扑排序的题目,讲解可见: https://blog.csdn.net/qq_41713256/article/details/80805338 分析:因为只要求两点中任一点可到达另一点,也就是只要求是弱连通图。首先强连通分量内部肯定是可以是任意到达的,我们先利用Tarjan进行缩点形成一个有向无环图(DAG),在这个基础上我们进行拓扑排序,只要存在一条路径连接所有点的话,那么肯定是可以到达了,基于此我们在拓扑排序时,如果每一层都只有一个点入度为0 ,就可以得到唯一的一条路径连接所有点了,也就是说这时候就可以到达了。 #include<bits/stdc++.h> #define maxn 1011 using namespace std; vector<int>G[maxn],new_G[maxn]; stack<int>s; int n,m; int dfn[maxn],vis[maxn],low[maxn],color[maxn],colornum,cnt,in[maxn]; //in数组记录入度 bool toposort(int n){ queue<int>q;

HDU - 5934 Bomb (tarjan)

我们两清 提交于 2019-11-26 09:00:40
题意:给出你N个炸弹坐标,以及每个的爆炸范围,引爆炸弹所需的花费。如果某个炸弹在另一个的爆炸范围以内,则可以被另一个炸弹引爆(间接引爆)。问引爆所有炸弹所需的最小花费 思路:把炸弹看作一个点,间接引爆就相当于一条有向边。最终所形成的图中,我们去找强连通分量。每个分量中花费最小的cost 以及 入度为0的 炸弹cost之和 即为所求。 这里我们使用tarjan来缩点求强连通分量。 完整代码:(注意 要开long long) #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <stack> #include <cmath> #define ll long long #define IOS ios::sync_with_stdio(0); cin.tie(0); using namespace std; const int maxn = 1e3+3; const int maxe = 1e6+1; struct Edge{ int v,next; }edge[maxe]; struct Bomb{ ll x,y; ll c; double r; }bomb[maxn]; int head[maxn]; int indeg[maxn],outdeg[maxn];

UVA - 796 Critical Links (tarjan,无向图桥)

女生的网名这么多〃 提交于 2019-11-26 07:40:32
题意:给出一个无向图,然后你要输升序输出该图中 所有的桥。 思路:使用tarjan对桥的求法性质: 当且仅当无向边(u,v)为树枝的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u-v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥。 如果v能上翻到u那么u-v就是一个环,删除其中一条路径后,能然是连通的。所以最总就是使用low(v)>dfn(u)来判断是否为桥 完整代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <stack> using namespace std; typedef long long LL; const double eps = 1e-8; const int inf = 0x3f3f3f3f;const int maxn = 1e3+10; const int max_edge = 1e6+5; struct Edge { int to, next; bool cut; }edge[max_edge]; int tot, head[maxn]; int id, dfn[maxn], low[maxn];