tarjan算法求解强连通分量问题
Part1:有向图的强连通分量:
一个连通图只有一个联通分量就是自身,非连通图有多个连通分量。
在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。
而有向图G的极大强连通子图S,即添加任意顶点都会导致S失去强连通的属性,则称S为G的强连通分量。
DFS生成树:
对于一棵的dfs生成树,树边可以分为以下4类:
1.树枝边<x,y> x是y的父节点。
2.前向边<x,y> x是y的祖宗节点。
3.后向边<x,y> 返祖边y是x的祖宗节点。
4.横叉边<x,y> x已经被dfs遍历过,但x不是y的一个祖宗节点
根据DFS生成树如何找到强连通分量:
如果结点 u 是某个强连通分量在搜索树中遇到的第一个结点,那么这个强连通分量的其余结点肯定是在搜索树中以 u为根的子树中。结点 u被称为这个强连通分量的根。
反证法:假设有个结点 v在该强连通分量中但是不在以 u为根的子树中,那么 u到 v的路径中肯定有一条离开子树的边。但是这样的边只可能是横叉边或者反祖边,然而这两条边都要求指向的结点已经被访问过了,这就和 u 是第一个访问的结点矛盾了,命题得证。
为了找到强连通分量在搜索树中的第一个节点,我们引入时间戳(timestamp)
Tarjan 算法求强连通分量
在 Tarjan 算法中为每个结点 u维护了以下几个变量:
dfn(u)表示遍历到u时的时间戳;
low(u)表示从u开始遍历到的最小时间戳;
那么如果low[u]==dfn[u],u就是我们所求的强连通分量在搜索树中的第一个结点。
tarjan 缩点
找到所有强连通分量后,遍历i的所有邻点,如果i和j不在同一连通分支,那么在这两个联通分支之间连一条有向边就能缩点,而且缩点后的图时DAG(拓扑图)。
参考视频:
[算法]轻松掌握tarjan强连通分量_哔哩哔哩_bilibili
1174. 受欢迎的牛
每一头牛的愿望就是变成一头最受欢迎的牛。
现在有 N 头牛,编号从 1 到 N,给你 M 对整数(A,B),表示牛 A 认为牛 B 受欢迎。
这种关系是具有传递性的,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么牛 A 也认为牛 CC 受欢迎。
你的任务是求出有多少头牛被除自己之外的所有牛认为是受欢迎的。
输入格式
第一行两个数 N,M;
接下来 M 行,每行两个数 A,B,意思是 A 认为 B 是受欢迎的(给出的信息有可能重复,即有可能出现多个 A,B)。
输出格式
输出被除自己之外的所有牛认为是受欢迎的牛的数量。
数据范围
1≤N≤104,
1≤M≤5×104
输入样例:
3 3
1 2
2 1
2 3
输出样例:
1
样例解释
只有第三头牛被除自己之外的所有牛认为是受欢迎的。
思路:将受欢迎看成一种关系,牛看成点,x欢迎y就是从x->y 有一条有向边,假设s、t是一部分被所有牛认为是受欢迎的牛,(s与其他任何点联通,t也与其他任何点联通)同时s、t互相认为对方是受欢迎(互相连通)的因此s、t是强联通的,这就说明被所有牛都受欢迎的牛构成的图是原图的一个强连通分量,利用tarjan算法求出原图的所有强连通分量;当一个强连通分量的出度为0,则该强连通分量中的所有点都被其他强连通分量的牛欢迎。但假如存在两及以上个出度=0的牛(强连通分量) 则必然有一头牛(强连通分量)不被所有牛欢迎,这就说明满足条件的牛构成的图是原图的唯一的一个强连通分量。
code:
#include<bits/stdc++.h>
using namespace std;
const int N =5e4+10;
int e[N],h[N],ne[N],idx;
int dfn[N],timestamp;
int low[N],id[N],scc_cnt;
bool in_stk[N];
int stk[N],top;
int sz[N];
int dout[N];
int n,m;
void add(int a,int b ){e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u){dfn[u]=low[u]=++timestamp;stk[++top]=u;in_stk[u]=true;for(int i=h[u];~i;i=ne[i]){int j=e[i];if(!dfn[j]){tarjan(j);low[u]=min(low[u],low[j]);}else if(in_stk[j]){low[u]=min(low[u],dfn[j]);}}if(low[u]==dfn[u]){++scc_cnt;int y;do{y=stk[top--];in_stk[y]=false;id[y]=scc_cnt;sz[scc_cnt]++;}while(y!=u);}
}
signed main(){cin>>n>>m;memset(h,-1,sizeof h);while(m--){int a,b;cin>>a>>b;add(a,b);}for(int i=1;i<=n;i++){if(!dfn[i]){tarjan(i);}}for(int i=1;i<=n;i++){for(int j=h[i];~j;j=ne[j]){int k=e[j];int a=id[i],b=id[k];if(a!=b){dout[a]++;}}}int zeros=0,sum=0;for(int i=1;i<=scc_cnt;i++){if(!dout[i]){zeros++;sum+=sz[i];if(zeros>1){sum=0;break;}}}cout<<sum<<endl;return 0;
}
tarjan算法求解强连通分量问题相关推荐
- 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图
文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...
- tarjan算法总结 (强连通分量+缩点+割点),看这一篇就够了~
文章目录 一.tarjan求强连通分量 1:算法流程 2:模板 二.tarjan缩点 1:相关定义 2:算法流程 三.tarjan求割点.桥 1.什么是割点 2.割点怎么求? 3.割点tarjan模板 ...
- tarjan算法(强连通分量与割点)
tarjan算法可以求有向图的割点割边强连通分量(还有一些奇奇怪怪的操作) 我只会割点和强连通分量,割边(和缩点)以后可能会加,如果是来看割边的话,现在跑还来得及.. (先来一张有向图叭) 用这张图, ...
- POJ2186——并查集+Tarjan算法求强连通分量
算法讨论:这题陷阱比较多.首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中.这个我们用并查集来实现就可以了.强连通分量的求法就很简单了,正 ...
- 解题报告:luogu P2341 受欢迎的牛(Tarjan算法,强连通分量判定,缩点,模板)
题目链接:洛谷 受欢迎的牛 基本上算是一道模板题 根据题意,如果有环,意味着这个环里的牛都互相喜欢 我们可以先求出环,然后把每一个环都看作一个点,这样整个图就变成了一个DAG(有向无环图) 看有几个点 ...
- 算法竞赛——强连通分量
强连通分量 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图也可以说,在强连 ...
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
http://blog.csdn.net/geniusluzh/article/details/6619575 在说Tarjan算法解决桥和边双连通分量问题之前我们先来回顾一下Tarjan算法是如何求 ...
- 双连通图强连通图概念解释以及tarjan算法求解该类问题总结
最近看了看类的相关题,感觉简单的题过于模板,但是对于难题的转化,如果对与这方面的概念不清楚,很难写,故总结一下. PS:博客里部分内容会和离散数学中的图论知识有联系,如果没有了解过相关知识可能比较难理 ...
- Targan 算法[有向图强连通分量]
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(stronglyconnected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大 ...
最新文章
- P1449 后缀表达式
- Windows Forms高级界面组件-快捷菜单
- android 如何适配屏幕
- MySQL查询的性能优化
- 为什么 SAP Spartacus 不手动导入 UserAccountModule,就看不到 LoginForm?
- JAVA遍历map元素
- 江苏省计算机二级c语言备考,江苏省计算机二级C语言考试备考指南
- 查看 java opts,如何在命令提示符中检查JAVA_OPTS值?
- linux中wine文件夹在哪,linux下wine的使用
- WSDM2019|门限注意力自编码在内容感知推荐中的应用(已开源)
- python计算圆的周长_Python计算圆周长和面积
- 短信通知接口json报文开发设计总结
- mfc 中文乱码转换为正常中文_中文编码转换
- 数据分析 VS 算法模型,如何高效分工合作?
- 告诉你什么是挖洞最清奇的脑回路
- 正则表达式 - Python 正则表达式 学习笔记 最全整理
- win11怎么共享文件夹 Windows11共享文件夹的设置方法
- C2B的未来:大数据定制
- idea调整代码标签编辑器标签editor tabs的横排和竖排
- 2022深圳杯A题论文
热门文章
- Sparql与sql的比较
- CouchDB与CouchBase的比较
- 微信小程序swiper上下滑动卡顿
- C# 及excel中【总体方差】、【样本方差】的计算公式
- 实战派来了!聊聊百度智能运维的“前世今生” | 技术沙龙
- key 、primary key 、unique key 与index区别
- python+sklearn实现决策树模型
- 四个有意义的哲理故事
- 今天面完了聚成网络的php研发,面经一枚,为自己攒人品。
- Date int java_java.util.Calendar.set(int year, int month, int date)方法实例