Tarjan算法

Tarjan算法可以应用在求解 强连通分量,缩点,桥,割点,双连通分量,LCA等
关于

文章目录

    • 强连通分量
      • 代码
      • 题目
    • tarjan求割点
      • 割点概念
      • 流程
      • 代码:
    • 求无向图的割边/桥
      • 理解:
      • 代码:
    • 强连通分量缩点
      • 大致流程:
      • 代码:
      • 例题
    • Tarjan求LCA
      • 关于LCA本人博客讲解
      • 例题
    • 双连通分量
      • 点双连通图
      • 边双连通图

对于一个连通图,如果任意两点至少存在两条点不重复路径,则称这个图为点双连通的(简称双连通);如果任意两点至少存在两条边不重复路径,则称该图为边双连通的。点双连通图的定义等价于任意两条边都同在一个简单环中,而边双连通图的定义等价于任意一条边至少在一个简单环中。对一个无向图,点双连通的极大子图称为点双连通分量(简称双连通分量),边双连通的极大子图称为边双连通分量。

强连通分量

我粗略提一下里面的参量:
dfn[]表示该节点在DFS的过程中第一次搜索到的次序(也就是第几个遍历到的点)
low[]一开始和dfn[]相等,但在回溯过程中不断维护,最终成为这个强连通分量中dfn的最低值
节点u是某个强连通分量的根等价于dfn[u]和low[u]相等

代码

void Tarjan(int u)
{vis[u]=1;low[u]=dfn[u]=cnt++;for(int i=0;i<mp[u].size();i++){int v=mp[u][i];if(dfn[v]==0){Tarjan(v);//如果这个点还没访问过,从这点继续开始找 low[x] = min(low[x],low[v]);}if(vis[v]==1)low[u]=min(low[u],dfn[v]);//更新时间戳 }if(dfn[u]==low[u]){sig++;}
}

题目

tarjan求割点

割点概念

割点:无向连通图中,去掉一个顶点及和它相邻的所有边,图中的连通分量数增加,则该顶点成为割点
求割点可以不用栈结构

流程

对于根节点,如果有两个以上的子树就说明是割点,因为取出后,子树就会分离
对于非根节点,对于边(u,v),如果low[v]>=dfn[u],此时u就是割点
tarjan(u,r)
u:表示当前点
r表示的是树的root
所以r不变,变的是u

代码:

child用来统计孩子数目
cut[x]:表示x是否为割点

// u:当前点 r:本次搜索树的root
void tarjan(ll u, ll r) {dfn[u] = low[u] = ++deep;ll child = 0;for (unsigned i = 0; i < g[u].size(); i++) {ll v = g[u][i];if (!dfn[v]) {tarjan(v, r);low[u] = min(low[u], low[v]);if (low[v] >= dfn[u] && u != r)cut[u] = 1;//不是根而且他的孩子无法跨越他回到祖先if (r == u)child++; //如果是搜索树的根,统计孩子数目}low[u] = min(low[u], dfn[v]);//已经搜索过了}if (child >= 2 && u == r)//如果根节点的子树数量大于等于2 ,将根节点去掉之后两颗子树就分离了cut[r] = 1;
}

求无向图的割边/桥

理解:

割边:在一个无向图中,去掉一条边(u, v),可以使图的连通分量增多的边, 就是割边,也称做桥

原理:利用tarjan算法, 对于一条边的起点u,终点v,如果满足条件 low[v] > dfn[u], 那么(u, v)就是一条割边, 因为这意味着不存在其他的边使得v可以回到u, 那么割掉就使图分离了.
需要注意的是跟割点不同, 没有等于号, 否则说明存在其他边回到起点, 那么就不是割边。
tarjan(int u,int pre)//pre表示u的父亲节点

代码:

代码选自Network POJ-3694的题解

 if(!dfn[v]){Tarjan(v, u);low[u] = min(low[u], low[v]);if(low[v]>dfn[u])   //isbridge[v]表示在树中,以v为儿子结点的边是否为桥{isbridge[v] = 1;sum_bridge++;//桥的数量加一} }elselow[u] = min(low[u], dfn[v]);

强连通分量缩点

缩点的作用:
1.可以把一个有向带环图,变成一个有向无环图(DAG),(因为我们把环给缩成一个集体)这样我们就可以直接当做无环图做就可以
2.可以算缩点后每个点的出度
图来自
在这里插入图片描述

大致流程:

在用Tarjan求完强连通分量后,可以用一个数组color进行标记,将同一个连通分量的点标记为相同数值,这样再遍历一遍所有边之后,如果有个边u->v的两侧不是一个数值,说明不再一个连通分量,则就从u所在颜色向v所在颜色生成一个边,(也就是u所在的连通分量向v所在的连通分量生成一条边),最后这些新生成的边就是组成新的图就是缩点后的图。。
我们可以在此基础上计算缩点后的出入度

代码:

const int MAXN = 5e3 + 20;
const int MAXM = 1e6 + 10; 
int head[MAXN], cnt, tot, dfn[MAXN], low[MAXN], color[MAXN], col;
bool vis[MAXN];
int degree[MAXN];
stack<int> stc;
int n, m;
struct Edge {int to, next, dis;	
}edge[MAXM << 1];
void add_edge(int u, int v, int dis) {edge[++cnt].to = v;edge[cnt].next = head[u];head[u] = cnt; 
}
void Tarjan(int x) {vis[x] = 1;dfn[x] = low[x] = ++tot;stc.push(x);for(int i = head[x]; i; i = edge[i].next) {int to = edge[i].to;if (!dfn[to]) {Tarjan(to);low[x] = min(low[x], low[to]);} else if( vis[to] ) {low[x] = min(low[x], dfn[to]);}}//以上为正常的tarjan求强连通分量 if(dfn[x] == low[x]) {col ++;while(true) {int top = stc.top();//栈中最上面的点 stc.pop();color[top] = col;	//给同一连通分量的点上相同的颜色,相当于缩点 vis[top] = 0;//	cout << top << " ";if(top == x) break; //遍历完后退出 }//cout << endl;}
}
void solve(){for(int i = 1; i <= n; ++i) {if(!dfn[i])Tarjan(i);}for(int x = 1; x <= n; ++x) {	//遍历 n个节点 for(int i = head[x]; i; i = edge[i].next) {	//缩点后  每个点的出度 int to = edge[i].to;if(color[x] != color[to]) {degree[color[x]] ++;//计算出度 }}}
}
void init () {cnt = 1;tot = 0;col = 0;memset(vis, 0, sizeof(vis));memset(head, 0, sizeof(head));memset(dfn, 0, sizeof(dfn));memset(low, 0, sizeof(low));memset(degree, 0, sizeof(degree));memset(color, 0, sizeof(color));while(!stc.empty()) stc.pop();
}
int main () {std::ios::sync_with_stdio(false);cin.tie(0);while(cin >> n && n) {cin >> m;init();int x, y;for(int i = 1; i <= m; ++i) {cin >> x >> y;add_edge(x, y, 0);}solve();} return 0;
}

例题

The Bottom of a Graph Poj 2553

Tarjan求LCA

关于LCA本人博客讲解

例题

Network POJ-3694

双连通分量

点双连通图

若一个无向连通图不存在割点,则称它为“点双连通图”。

边双连通图

若一个无向连通图不存在割边,则称它为“边双连通图”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319968.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[集训队作业2018] 万圣节的积木(李超线段树)

传送门 设最底层为第1层&#xff0c;倒数第二层为第2层&#xff0c;以此类推。 发现若第111 ~ iii层构成的积木稳定&#xff0c;第111 ~ jjj (j>ij>ij>i)构成的积木也稳定&#xff0c; 那么第i1i1i1 ~ jjj层构成的积木一定也是稳定的。 所以我们只要找到所有的iii满…

Ocelot简易教程(一)之Ocelot是什么

简单的说Ocelot是一个用.NET Core实现并且开源的API网关技术。可能你又要问了&#xff0c;什么是API网关技术呢&#xff1f;Ocelot又有什么特别呢&#xff1f;我们又该如何集成到我们的asp.net core程序中呢&#xff1f;下面我会通过一些列通俗易懂的教程来为大家讲解。今天的这…

P5516-[MtOI2019]小铃的烦恼【期望dp,线性消元】

正题 题目链接:https://www.luogu.com.cn/problem/P5516 题目大意 nnn个字母的一个字符串&#xff0c;每次随机选取两个不同的位置(x,y)(x,y)(x,y)让第xxx个位置的字符变成第yyy个位置的字符。 求期望多少次能够把所有字符变成同一个。 解题思路 因为最终状态很多&#xff0…

如何在你的项目中集成 CAP【手把手视频教程】

前言之前录制过一期关于CAP的视频&#xff0c;但是由于当时是直播时录制的视频&#xff0c;背景音比较杂所以质量有点差。这次的视频没有直播&#xff0c;直接录制的&#xff0c;视频质量会好很多&#xff0c;第一遍录制完成之后发现播放到一半没有声音&#xff0c;所以又重新录…

【Splay】文艺平衡树(金牌导航 Splay-2)

#文艺平衡树 金牌导航 Splay-2 题目大意 给你一个1~n的序列&#xff0c;然后对序列的区间做若干次翻转&#xff0c;问你最后的序列 输入样例 5 3 1 3 1 3 1 4输出样例 4 3 2 1 5数据范围 1⩽n,m⩽105,1⩽l⩽r⩽n1\leqslant n,m\leqslant 10^5,1\leqslant l\leqslant r \l…

[集训队作业2018] 三角形(贪心,堆,线段树合并)

传送门 首先&#xff0c;在结点uuu放上w[u]w[u]w[u]个石子后&#xff0c;出于贪心考虑&#xff0c;下一步一定会把uuu的所有儿子vvv上的石子收回手中。 转换题意&#xff1a; 记cntcntcnt为当下树上的石子数&#xff0c;对每个结点uuu可以执行一次操作&#xff1a; step1. c…

P3527-[POI2011]MET-Meteors【整体二分,树状数组】

正题 题目链接:https://www.luogu.com.cn/problem/P3527 题目大意 mmm个格子形成的环&#xff0c;有nnn个集合&#xff0c;第iii个格子属于第oio_ioi​个集合&#xff0c;kkk次让环上一段的格子加上一个权值。 对于每个iii求出第iii个集合在多少次的时候它集合中的所有格子权…

.net core实践系列之短信服务-Sikiro.SMS.Api服务的实现

前言本篇会继续讲解Sikiro.SMS.Job服务的实现&#xff0c;在我写第一篇的时候&#xff0c;我就发现我当时设计的架构里Sikiro.SMS.Job这个可以选择不需要&#xff0c;而使用MQ代替。但是为了说明调度任务使用实现也坚持写了下。后面会一篇针对架构、实现优化的讲解。源码地址&a…

Drainage Ditches POJ1273

Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 93263 Accepted: 36174试题链接 文章目录Description题意&#xff1a;题解&#xff1a;代码&#xff1a;Dinic做法EK做法Description Every time it rains on Farmer John’s fields, a pond forms over Bessie’…

【主席树】可持久化数组(金牌导航 可持久化数据结构-3)

可持久化数组 金牌导航 可持久化数据结构-3 题目大意 给出一个序列a&#xff0c;让你执行若干操作&#xff0c;操作分为两种&#xff1a; 1.继承第v次操作后把第x个数改成y 2.查询第v次操作的第x个数的值 输入样例 5 10 59 46 14 87 41 0 2 1 0 1 1 14 0 1 1 57 0 1 1 88 …

[集训队作业2018] 复读机(生成函数,单位根反演)

传送门 subtask 1&#xff1a;d1d1d1 答案为knk^nkn。 subtask 2&#xff1a;n≤1000,k≤100n\leq1000,k\leq 100n≤1000,k≤100 设f[i][j]f[i][j]f[i][j]表示由iii个复读机来分jjj个时间点的方案数。 可以得到递推式&#xff1a; f[i][j]∑p0j[d∣p]Cjpf[i−1][j−p]f[i][j…

jzoj5097-[GDOI2017day1]取石子游戏【并查集,LCA】

正题 题目链接:https://gmoj.net/senior/#main/show/5097 题目大意 nnn个点的一棵树&#xff0c;每个节点有权值。对于每个点求树上所有权值去除掉他的子树的权值后的mexmexmex值。 解题思路 对于一个权值www&#xff0c;权值为www的所有点的LCALCALCA到根节点的路径上都不会…

P2756 飞行员配对方案问题【网络流24题】

P2756 飞行员配对方案问题 文章目录题目背景题解&#xff1a;代码&#xff1a;题目背景 第二次世界大战期间&#xff0c;英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的两名飞行员&#xff0c;其中一名是英国…

大数据分析中使用关系型数据库的关键点

相当一部分大数据分析处理的原始数据来自关系型数据库&#xff0c;处理结果也存放在关系型数据库中。原因在于超过99%的软件系统采用传统的关系型数据库&#xff0c;大家对它们很熟悉&#xff0c;用起来得心应手。在我们正式的大数据团队&#xff0c;数仓&#xff08;数据仓库H…

【FHQ treap】维护书架(金牌导航 无旋式treap-1)

维护书架 金牌导航 无旋式treap-1 题目大意 给出一个序列a&#xff0c;编号为1~n&#xff0c;让你做若干操作&#xff0c;操作有五种&#xff1a; 1.把第x个数放在最前面 2.把第x个数放在最后面 3.把第x个数和第x1x\pm 1x1个数交换 4.查询编号为i的数前面有多少个数 5.查询第…

P5488-差分与前缀和【NTT,生成函数】

正题 题目链接:https://www.luogu.com.cn/problem/P5488 题目大意 求一个长度为nnn的序列的kkk阶差分/前缀和。 解题思路 先考虑前缀和怎么做 搞出来生成函数就是(∑i0naixi)∗(∑i0∞xi)k(\sum_{i0}^na_ix^i)*(\sum_{i0}^{\infty}x^i)^k(i0∑n​ai​xi)∗(i0∑∞​xi)k 然…

图论复习——最小生成树MST

知识点 MST的构造 Boruvka算法常用于解决这类问题&#xff1a;给你n个点&#xff0c;每个点有点权&#xff0c;任意两个点之间有边权&#xff0c;边权为两个点权用过某种计算方式得出&#xff0c;求最小生成树。动图 MST上的确定性和存在性问题 最小生成树的两个性质&#xf…

Ocelot简易教程(二)之快速开始1

Ocelot是为.net core量身定做的&#xff0c;目前是基于 netstandard2.0进行构建的。.NET Core 2.1中如何使用呢&#xff1f;安装NuGet package使用nuget安装Ocelot及其依赖项。您需要创建一个netstandard2.0项目并将其Package安装到项目中。然后按照下面的“启动”和“ 配置”节…

【树链剖分】【线段树】树的统计(金牌导航 树链剖分-1)

树的统计 金牌导航 树链剖分-1 题目大意 给出一棵树&#xff0c;让你做若干操作&#xff0c;操作如下&#xff1a; 1.修改一个节点的值 2.查询两个节点之间路径的最大值 3.查询两个节点之间路径的和 输入样例 4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2…

P2761 软件补丁问题

文章目录题目描述题解&#xff1a;代码&#xff1a;添加链接描述题目描述 T 公司发现其研制的一个软件中有 n 个错误&#xff0c;随即为该软件发放了一批共 m 个补丁程序。每一个补丁程序都有其特定的适用环境&#xff0c;某个补丁只有在软件中包含某些错误而同时又不包含另一些…