有向图的强连通分量,割点与桥
有向图的强连通分量
1、Tarjan
![](/assets/blank.gif)
![](/assets/blank.gif)
/* Tarjan算法 复杂度O(N+M) */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std;const int MAXN=20010;//点数 const int MAXM=50010;//边数 struct Edge{int to,next; }edge[MAXM]; int head[MAXN],tot; int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc int Index,top; int scc;//强连通分量的个数 bool Instack[MAXN]; int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc //num数组不一定需要,结合实际情况void addedge(int u,int v){edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++; } void Tarjan(int u){int v;Low[u]=DFN[u]=++Index;Stack[top++]=u;Instack[u]=true;for(int i=head[u];i!=-1;i=edge[i].next){v=edge[i].to;if(!DFN[v]){Tarjan(v);if(Low[u]>Low[v])Low[u]=Low[v];}else if(Instack[v]&&Low[u]>DFN[v])Low[u]=DFN[v];}if(Low[u]==DFN[u]){scc++;do{v=Stack[--top];Instack[v]=false;Belong[v]=scc;num[scc]++;}while(v!=u);} } void solve(int N){memset(DFN,0,sizeof(DFN));memset(Instack,false,sizeof(Instack));memset(num,0,sizeof(num));Index=scc=top=0;for(int i=1;i<=N;i++)if(!DFN[i])Tarjan(i); } void init(){tot=0;memset(head,-1,sizeof(head)); }int main(){return 0; }
View Code
2、Kosaraju
![](/assets/blank.gif)
![](/assets/blank.gif)
/* Kosaraju算法,复杂度O(N+M) */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std;const int MAXN=20010; const int MAXM=50010; struct Edge{int to,next; }edge1[MAXM],edge2[MAXM]; //edge1是原图,edge2是逆图GT int head1[MAXN],head2[MAXN]; bool mark1[MAXN],mark2[MAXN]; int tot1,tot2; int cnt1,cnt2; int st[MAXN];//对原图进行dfs,点的结束时间从小到大排序 int Belong[MAXN];//每个点属于哪个连通分量(0~cnt2-1) int num;//中间变量,用来数某个连通分量中点的个数 int setNum[MAXN];//强连通分量中点的个数,编号0~cnt2-1 void addedge(int u,int v){edge1[tot1].to=v;edge1[tot1].next=head1[u];head1[u]=tot1++;edge2[tot2].to=u;edge2[tot2].next=head2[v];head2[v]=tot2++; } void DFS1(int u){mark1[u]=true;for(int i=head1[u];i!=-1;i=edge1[i].next)if(!mark1[edge1[i].to])DFS1(edge1[i].to);st[cnt1++]=u; } void DFS2(int u){mark2[u]=true;num++;Belong[u]=cnt2;for(int i=head2[u];i!=-1;i=edge2[i].next)if(!mark2[edge2[i].to])DFS2(edge2[i].to); } //点的编号从1开始 void solve(int n){memset(mark1,false,sizeof(mark1));memset(mark2,false,sizeof(mark2));cnt1=cnt2=0;for(int i=1;i<=n;i++)if(!mark1[i])DFS1(i);for(int i=cnt1-1;i>=0;i--)if(!mark2[st[i]]){num=0;DFS2(st[i]);setNum[cnt2++]=num;} }int main(){return 0; }
View Code
割点与桥
UVA 796 Critical Links
![](/assets/blank.gif)
![](/assets/blank.gif)
#include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <map> #include <vector> using namespace std; /* * 求 无向图的割点和桥 * 可以找出割点和桥,求删掉每个点后增加的连通块。 * 需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重 */ const int MAXN = 10010; const int MAXM = 100010; struct Edge {int to,next;bool cut;//是否为桥的标记 }edge[MAXM]; int head[MAXN],tot; int Low[MAXN],DFN[MAXN],Stack[MAXN]; int Index,top; bool Instack[MAXN]; bool cut[MAXN]; int add_block[MAXN];//删除一个点后增加的连通块 int bridge;void addedge(int u,int v) {edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut = false;head[u] = tot++; }void Tarjan(int u,int pre) {int v;Low[u] = DFN[u] = ++Index;Stack[top++] = u;Instack[u] = true;int son = 0;for(int i = head[u];i != -1;i = edge[i].next){v = edge[i].to;if(v == pre)continue;if( !DFN[v] ){son++;Tarjan(v,u);if(Low[u] > Low[v])Low[u] = Low[v];//桥//一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<Low(v)。if(Low[v] > DFN[u]){bridge++;edge[i].cut = true;edge[i^1].cut = true;}//割点//一个顶点u是割点,当且仅当满足(1)或(2) (1) u为树根,且u有多于一个子树。//(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,//即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)if(u != pre && Low[v] >= DFN[u])//不是树根 {cut[u] = true;add_block[u]++;}}else if( Low[u] > DFN[v])Low[u] = DFN[v];}//树根,分支数大于1if(u == pre && son > 1)cut[u] = true;if(u == pre)add_block[u] = son - 1;Instack[u] = false;top--; }void solve(int N) {memset(DFN,0,sizeof(DFN));memset(Instack,false,sizeof(Instack));memset(add_block,0,sizeof(add_block));memset(cut,false,sizeof(cut));Index = top = 0;bridge = 0;for(int i = 1;i <= N;i++)if( !DFN[i] )Tarjan(i,i);printf("%d critical links\n",bridge);vector<pair<int,int> >ans;for(int u = 1;u <= N;u++)for(int i = head[u];i != -1;i = edge[i].next)if(edge[i].cut && edge[i].to > u){ans.push_back(make_pair(u,edge[i].to));}sort(ans.begin(),ans.end());//按顺序输出桥for(int i = 0;i < ans.size();i++)printf("%d - %d\n",ans[i].first-1,ans[i].second-1);printf("\n"); } void init() {tot = 0;memset(head,-1,sizeof(head)); } //处理重边 map<int,int>mapit; inline bool isHash(int u,int v) {if(mapit[u*MAXN+v])return true;if(mapit[v*MAXN+u])return true;mapit[u*MAXN+v] = mapit[v*MAXN+u] = 1;return false; } int main() {int n;while(scanf("%d",&n) == 1){init();int u;int k;int v;//mapit.clear();for(int i = 1;i <= n;i++){scanf("%d (%d)",&u,&k);u++;//这样加边,要保证正边和反边是相邻的,建无向图while(k--){scanf("%d",&v);v++;if(v <= u)continue;//if(isHash(u,v))continue; addedge(u,v);addedge(v,u);}}solve(n);}return 0; }
View Code
转载于:https://www.cnblogs.com/bofengyu/p/5003327.html
有向图的强连通分量,割点与桥相关推荐
- 算法提高课-图论-有向图的强连通分量-AcWing 367. 学校网络:强连通分量、tarjan算法
文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 第一问:通过tarjan算法求出强连通分量并且缩点后,统计入度为0的点的个数p即可. 第二问,至少加几条边才能使图变成强连通分量?这 ...
- 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图
文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...
- C++Kosaraju找有向图的强连通分量算法(附完整源码)
C++Kosaraju找有向图的强连通分量算法 C++Kosaraju找有向图的强连通分量算法完整源码(定义,实现,main函数测试) C++Kosaraju找有向图的强连通分量算法完整源码(定义,实 ...
- 缩点(有向图的强连通分量)学习笔记
缩点(有向图的强连通分量)学习笔记 1.什么是强连通分量?: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路 ...
- 有向图的强连通分量(SCC)
有向图的强连通分量(SCC) 1. 有向图的强连通分量原理 原理 强连通分量是针对有向图来说的.如下的讲解默认都是针对有向图的. 连通分量:对于一个有向图中的一些点来说,如果任意两点都能相互到达,则称 ...
- 求无向图的连通分量或有向图的强连通分量—tarjan()ccf高速公路
概念定义: 在图论中,连通图基于连通的概念. 1. 连通(无向图): 若顶点Vi能通过路径到达Vj,那么称为Vi和Vj是连通的 对无向图:若从顶点Vi到顶点Vj有路径相连(当然从j到i也一定有路径), ...
- 有向图的强连通分量算法
有向图的强连通分量算法 强连通分量定义 在有向图中,某个子集中的顶点可以直接或者间接互相可达,那么这个子集就是此有向图的一个强连通分量,值得注意的是,一旦某个节点划分为特定的强连通分量后,此顶点不能在 ...
- 使用并查集实现查找无向图的连通分量和求解有向图的强连通分量
目录 1.无向图的连通分量 2.求解连通分量算法的实现 3.有向图的强连通分量 4.求解有向图的强连通分量 使用C语言实现并查集 有向图和无向图 1.无向图的连通分量 无向图G中,如果存在从顶点v1到 ...
- 【图论】—— 有向图的强连通分量
给定有向图 ,若存在 ,满足从 出发能到达 中所有的点,则称 是一个"流图"( Flow Graph ),记为 ,其中, 称为流图的源点. 在一个流图 上从 进行深度优先遍历 ...
最新文章
- BP算法双向传_链式求导最缠绵(深度学习入门系列之八)
- centos7 源码编译安装mysql 5.7.21
- 华为云客户端_效果图云渲染已成趋势,云渲染如何选择?
- SwiftUI之深入解析高级动画的几何效果GeometryEffect
- 分布式是写出来的(一)
- 2016-08-31
- 网站导航颜色停留_提高网站流量的方法有哪些?
- windows定时自动运行R脚本的正确姿势
- 实现IP地址归属地显示功能、号码归属地查询
- 仿高德地图点亮城市html,高德地图怎么点亮城市_高德地图点亮城市教程_3DM手游...
- OpenCV特征检测与匹配方法概览
- Android中使用Toast弹出信息提示时的用户体验优化
- 计算机网络连接黄感叹号,电脑连接路由器网络连接显示黄色感叹号的解决办法...
- 微众银行AI团队领衔推动人工智能国际标准的制定
- 【hbase问题】org.apache.hadoop.hbase.ipc.ServerNotRunningYetException: Server is not run
- Android String字符串截取方法总结
- JVM线程本地分配缓冲区(Thread Local Allocation Buffer)TLAB详解
- 软件开发部门经理岗位职责
- 谷歌二次验证 Google Authenticator
- 共勉。怎么摆脱习惯性刷手机的习惯?
热门文章
- [Aaronyang] 写给自己的WPF4.5 笔记17[Page实现页面导航]
- 三层BP神经网络的python实现
- ERROR 1372 (HY000): Password hash should be a 41-digit hexadecimal number;
- 【原】行内元素产生水平空隙是bug吗
- 标题: ZZ- Linux 系统裁减指南(LiPS)
- python 自动复制分类_leetcode python 常见分类问题模板(复制粘贴就能用) 更新中......
- python frombuffer_numpy.getbuffer和numpy.frombu
- 线上redis一般安在linux_Redis企业级应用-Linux安装搭建一个完整的linxu线上服务(上)...
- Mysql主从复制集群类型和搭建方法
- 怎么恢复linux定时器任务,定时操作 crontab at 以及恢复定时操作