tarjan

tarjan缩点(洛谷P387)

烂漫一生 提交于 2019-11-29 15:52:00
此题解部分借鉴于 九野的博客 题目分析 给定一个 \(n\) 个点 \(m\) 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。 假如没有后面这条限制的话,那图一定是一个 无环图 。因为有环的话我可以一直在环上跑,所以答案就没有一个上界 没有环的话我萌可以很自然地想到一个 \(O(n)\) 的 拓扑 \(dp\) 做法,先做入度为 \(0\) 的点,更新入度不为 \(0\) 的点,把更新后入度为 \(0\) 的点加入队列里,继续做之前的事情 现在考虑有环怎么做 有一个贪心的思路是,到环上就先把 环上的点 都走完,再从 环上任意一点 出发 其实这个环可以看做一个 大点 ,也就是我们今天要介绍的主角 \(\to\) 缩点 tarjan缩点 下面这张图是从 九野的博客 那 copy 过来的 把可以互相抵达的 点集 叫做一个 连通分量 最大的那个可以互相抵达的点 点集 即为 强连通分量 特别的,单个的点也可以是 强连通分量 比如说 : \(\{ 4, 5 \}\) 是一个 联通分量 ,而 ${4,5,6 } $ 则是一个 强连通分量 (一个大点) tarjan的过程就是通过 dfs 找强连通分量(大点)的过程 对图 dfs 一下,遍历所有未遍历过的点 ,会得到一个 有向树

强连通分量

限于喜欢 提交于 2019-11-29 14:20:15
tarjan 基于深度优先搜索,用于寻找有向图中的连通块。 主要代码如下: inline void tarjan(int x){ dfn[x]=low[x]=++idx; vis[x]=1; sta[++top]=x; for(int i=head[x];i;i=e[i].nxt){ int v=e[i].v; if(!dfn[v]){//还未访问过这个节点 tarjan(v); low[x]=min(low[x],low[v]); } else if(vis[v]==1){//这个节点在栈中 low[x]=min(low[x],dfn[v]); } } if(dfn[x]==low[x]){//找到一个强联通分量 ++cnt; while(x!=sta[top]){ vis[sta[top]]=0; qlt[sta[top]]=cnt;//染色,标记这个节点属于第几号强联通分量 siz[cnt]++;//记录这一个连通块的节点数 top--; } vis[x]=0;//还要将这个节点弹出来 qlt[x]=cnt; siz[cnt]++; top--; } } 如果是要遍历整张图找到所有的连通块,通常还要加这句 for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } 因为图中不一定全部都是联通的。 每一个点只访问了一次

tarjan算法——边双连通分量

倖福魔咒の 提交于 2019-11-29 09:49:38
简介: 还是采用tarjan缩点,如果边(u,v)是桥,那么显然dfn[v]=low[v],则v此时栈中的集合为一个边连通分量。 代码: 1 void tarjan(int x,int &sccnum,int from) { 2 sta[++cnt]=x; 3 vis[x]=1; 4 dfn[x]=++lay; 5 low[x]=lay; 6 bool flag=false; 7 for(int i=head[x];~i;i=e[i].net) { 8 int v=e[i].v; 9 if(v==from&&!flag) { ///如果是重边的情况 10 flag=true; 11 continue; 12 } 13 if(!dfn[v]) { 14 tarjan(v,sccnum,x); 15 low[x]=min(low[x],low[v]); 16 } 17 else if(vis[v]==1) 18 low[x]=min(low[x],low[v]); 19 } 20 if(dfn[x]==low[x]) { ///有割边 21 ++sccnum; 22 do { 23 f[sta[cnt]]=sccnum; ///标记为同一集合 24 vis[sta[cnt]]=2; 25 }while(sta[cnt--]!=x); 26 } 27 } View Code 来源:

【算法入门】Tarjan求解图的强连通分量

有些话、适合烂在心里 提交于 2019-11-29 06:38:56
说在前面 这篇博客真的是针对新手的一篇Tarjan求图的强连通分量的博文,因为博主自身刚刚学习,也顺便写个博文记录一下,所以正好体现了新手如何去逐步了解Tarjan算法。 一、基础知识 在去学习了解Tarjan算法之前,我们首先要了解什么是强连通以及什么是强连通分量。(没有术语,都是大白话) 强连通 对于一个图中的某两个点,如果其相互可达,则说这两个点是强连通的。举例来说就是有一个图中有A、B两个顶点,可以找到一条路径由A到达B,也可以找到一条路径由B到达A,那么就说A点和B点是强连通的。 强连通图 为了介绍强连通分量,这里再引入一个强连通图的概念。对于一个图来说,任意两个点都是强连通的,那么该图为一个强连通图。 强连通分量 非强连通图的极大强连通子图,称为强连通分量。强连通图上述已经介绍过了,极大强连通子图的意思就是,这个图中的所有可能的强连通的点都包含在子图中了,再加入会使其不能再保证强连通性。"极大"这个概念学计算机的应该经常会遇到。 二、Tarjan模板代码解释 由于我自己对于Tarjan算法也是初学,一开始也找不到一个很好的博客可以很详细的进行解释,下面我也就是分享一种学习的思路吧,可以帮你更快的掌握。 首先,对于Tarjan算法,有一些细节你可以先不要考虑,就是dfn和low具体的工作方式。在初学的时候,你可以暂时将对dfn数组和low数组的认识停留在这样一个层面上:

关于Tarjan

↘锁芯ラ 提交于 2019-11-29 03:15:57
我真是猪脑子哇 学姐讲的全被我吃了 qwq 今天又温习了一下, 觉得还是写下来比较好 毕竟我的记忆力 犹如冬风 不仅刷刷刷的还飕飕飕的 关于割点与割边(桥): 割点 :删它及其连边去之后图变为不连通 能够成为割点的条件 : 1.对于根节点,有两棵或以上子树 2.对于非根非叶节点, 某棵子树没有指向u的祖先的回边 割边 :删掉这条边之后图变为不连通 成为割边的条件 :(u,v)为树边且low[v]>dfn[u]时 原因: 表示v节点只能通过该边与u相连 例题:洛谷 P3388 【模板】割点(割顶) 代码: #include <iostream> #include <cstdio> #include <cstring> #define N 100010 using namespace std; struct node { int next, to; }e[N * 2]; int n, m, idx, cnt, tot; int head[N], dfn[N], low[N]; bool cut[N]; void add (int x, int y) { e[++cnt].next = y; e[cnt].to = head[x]; head[x] = cnt; } void tarjan (int u, int fa) { dfn[u] = low[u] = ++idx; int

Tarjan求强连通分量模板

北城余情 提交于 2019-11-29 02:17:57
1 inline void tarjan(int x) { 2 int v; 3 dfn[x] = low[x] = ++sum; 4 a.push(x); 5 _in[x] = 1; 6 for(int i = head[x];i != -1; i = e[i].next) { 7 v = e[i].to; 8 if(!dfn[v]) { 9 tarjan(v); 10 low[x] = min(low[x],low[v]); 11 } 12 else if(_in[v]) 13 low[x] = min(low[x],dfn[v]); 14 } 15 if(dfn[x] == low[x]) { 16 csp++; 17 do { 18 v = a.top(); 19 a.pop(); 20 _in[v] = false; 21 num[csp]++; 22 belong[v] = csp; 23 } 24 while(v != x); 25 } 26 } 来源: https://www.cnblogs.com/lipeiyi520/p/11440063.html

tarjan强连通缩点——cf711D

半城伤御伤魂 提交于 2019-11-28 23:08:45
模板题 #include<bits/stdc++.h> using namespace std; #define ll long long #define N 500005 #define mod 1000000007 int n,a[N]; vector<int>G[N]; int cnt,dfn[N],low[N],ind,stk[N],ins[N],top; vector<int>scc[N]; void tarjan(int x){ dfn[x]=low[x]=++ind; stk[++top]=x,ins[x]=1; for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); } else if(ins[y]) low[x]=min(low[x],low[y]); } if(dfn[x]==low[x]){ cnt++;int y; do{ y=stk[top--]; ins[y]=0; scc[cnt].push_back(y); }while(y!=x); } } ll Pow(ll a,ll b){ ll res=1; while(b){ if(b%2) res=res*a%mod; b>>=1;a=a*a%mod; }

poj2533 The Bottom of a Graph(Tarjan+缩点)

梦想的初衷 提交于 2019-11-28 19:51:33
Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 12659 Accepted: 5211 Description We will use the following (standard) definitions from graph theory. Let V be a nonempty and finite set, its elements being called vertices (or nodes). Let E be a subset of the Cartesian product V×V , its elements being called edges. Then G=(V,E) is called a directed graph. Let n be a positive integer, and let p=(e 1 ,...,e n ) be a sequence of length n of edges e i ∈E such that e i =(v i ,v i+1 ) for a sequence of vertices (v 1 ,...,v n+1 ) . Then p is called a path from vertex v 1 to vertex v n+1 in G

危险道路(Tarjan+割边/桥)

时光总嘲笑我的痴心妄想 提交于 2019-11-28 19:04:57
题目描述 天凯是苏联的总书记。苏联有n个城市,某些城市之间修筑了公路。任意两个城市都可以通过公路直接或者间接到达。 天凯发现有些公路被毁坏之后会造成某两个城市之间无法互相通过公路到达。这样的公路就被称为dangerous pavement。 为了防止美帝国对dangerous pavement进行轰炸,造成某些城市的地面运输中断,天凯决定在所有的dangerous pavement驻扎重兵。可是到底哪些是dangerous pavement呢?你的任务就是找出所有这样的公路。 输入格式 第一行n,m(1<=n<=100000, 1<=m<=300000),分别表示有n个城市,总共m条公路。 以下m行每行两个整数a, b,表示城市a和城市b之间修筑了直接的公路。 输出格式 输出有若干行。每行包含两个数字a,b(a < b),表示 < a,b >是dangerous pavement。请注意:输出时,所有的数对< a,b>必须按照a从小到大排序输出;如果a相同,则根据b从小到大排序。 输入 6 6 1 2 2 3 2 4 3 5 4 5 5 6 输出 1 2 5 6 Tarjan算法割边的模板 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N=1e5+5; 5 int n,m,dep; 6 int dfn

割点

我是研究僧i 提交于 2019-11-28 08:37:58
INTRODUCTION: 在一个 无向图 中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的 连通分量 增多,就称这个点集为割点 集合 。 如果某个割点集合只含有一个顶点X(也即{X}是一个割点集合),那么X称为一个割点。--百度百科 首先,什么是割点? 在一个有N个节点,M条边的有向图中, 若删去一个点,以及所有与这个节点直接相连的边 , 会使该图不连通、或出现更多互不连通的子图(原图本身就不连通的情况) ,则称这个点为割点。 那么不难想到割点的一种求法: 一、暴力枚举: 枚举每一个节点,判断该节点是否是割点( 没有什么是暴力解决不了的 ) 不过显然暴力枚举太慢了,出题人也不想让你这么轻松就AC 因此,可以用以下两种方法快速的求出割点: 二、DFS树: 首先来设想一下,假如我们用DFS来遍历一张无向图连通图,保证每个点只被遍历到一次,然后将遍历时经过的每一个点,每一条边取出,组成一个新的联通图,显而易见: 这张新图必然是一棵树。 我们称这棵树为DFS树,同时不难看出,由于遍历时所选的根节点不同,遍历的顺序不同,所以这颗DFS树并不唯一,不过这对于求割点而言影响不大,所以只要任意求出一颗DFS树就可以了 对于原图而言,我们将构成DFS树的边称为树边,不属于DFS树的边称为非树边 存在一个结论:对于每一条非树边,他