强联通分量

1.概念

有向图G中,如果两点互相可达,则称这两个点强连通,如果G中任意两点互相可达,则称G是强连通图。

定理: 1、一个有向图是强连通的,当且仅当G中有一个回路,它至少包含每个节点一次。

2、非强连通有向图的极大强连通子图,称为强连通分量(SCC即Strongly Connected Componenet)。

任意有向图都可以分解成若不相干的强连通分量,这就是强连通分量分解。把分解后的强连通分量缩成一个顶点,就得到了一个DAG(有向无环图)。

  2.Korasaju算法

强连通分量分解可以通过两次简单的DFS实现。第一次DFS时,选取任意顶点作为起点,遍历所有尚未访问过的顶点,并在回溯前给顶点标号(post order,后序遍历)。对剩余的未访问过的顶点,不断重复上述过程。

完成标号后,越接近图的尾部(搜索树的叶子),顶点的标号越小。第二次DFS时,先将所有边反向,然后以标号最大的顶点为起点进行DFS。这样DFS所遍历的顶点集合就构成了一个强连通分量。之后,只要还有尚未访问的顶点,就从中选取标号最大的顶点不断重复上述过程。

package 图论;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;public class 强联通分量_Korasaju {static int n, m;static ArrayList<Integer>[] list1;static ArrayList<Integer>[] list2;static ArrayList<Integer> vs = new ArrayList<Integer>();static boolean[] vis;static int[] collection;// 强联通分量集合,同一个集合数字相同static void init() {list1 = new ArrayList[n];for (int i = 0; i < n; i++) {list1[i] = new ArrayList<Integer>();}list2 = new ArrayList[n];for (int i = 0; i < n; i++) {list2[i] = new ArrayList<Integer>();}vis = new boolean[n];collection = new int[n];}static void dfs(int u) {vis[u] = true;for (int j = 0; j < list1[u].size(); j++) {int v = list1[u].get(j);if (!vis[v]) {dfs(v);}}// 标号vs.add(u);}//搜索反向图static void rdfs(int u, int k) {vis[u] = true;collection[u] = k;// 顶点u属于第k个强联通分量集合for (int j = 0; j < list2[u].size(); j++) {int v = list2[u].get(j);if (!vis[v]) {rdfs(v, k);}}}static void scc() {// 遍历每一个顶点for (int i = 0; i < n; i++) {if (!vis[i])dfs(i);}for (int i = 0; i < n; i++) {vis[i] = false;}int k = 0;for (int i = vs.size() - 1; i >= 0; i--) {int v = vs.get(i);if (!vis[v]) {rdfs(v, k++);}}System.out.println("强联通分量集合:");System.out.println(Arrays.toString(collection));}public static void main(String[] args) {// TODO Auto-generated method stubScanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();init();for (int i = 0; i < m; i++) {int u = sc.nextInt() - 1;int v = sc.nextInt() - 1;list1[u].add(v);list2[v].add(u);// 反向建图}scc();}}
/*
12
16
12 11
11 8
11 10
8 10
10 9
9 8
9 7
7 6
5 7
6 5
6 4
6 3
4 3
2 3
3 2
4 1
*/

3.Tarjan算法

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

那么怎么判断呢?

强连通分量是由若干个环组成的。所以,当有环形成时(也就是搜索的下一个点已在栈中),我们将这一条路径的low值统一,即这条路径上的点属于同一个强连通分量。

代码如下:

package 图论;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;public class 强联通分量_tarjan {static int n, m, cnt, scc_cnt;static ArrayList<Integer>[] list;static boolean[] vis;static int[] dfn, low, num;static Stack<Integer> stack = new Stack<Integer>();static void init() {list = new ArrayList[n];for (int i = 0; i < n; i++) {list[i] = new ArrayList<Integer>();}vis = new boolean[n];dfn = new int[n];low = new int[n];num = new int[n];}static void tarjan(int u) {vis[u] = true;dfn[u] = low[u] = ++cnt;stack.add(u);for (int i = 0; i < list[u].size(); i++) {int v = list[u].get(i);// 如果下一个节点没有访问过if (!vis[v]) {tarjan(v);low[u] = Math.min(low[u], low[v]);// 如果下一个节点已经被访问过了,且不属于任何一个连通分量} else if (stack.contains(v)) {// v是连通分量一个节点,统一low值low[u] = Math.min(low[u], dfn[v]);}}// 如果节点u是强连通分量的根// 满足强连通分量的要求,当前节点u为该强连通分量最早发现的节点if (dfn[u] == low[u]) {scc_cnt++;// 强联通分量个数while (true) {int v = stack.pop();// 将v退栈,为该强连通分量中一个顶点num[v] = scc_cnt;// 同一个连通分量的同一个数字if (u == v)break;}}}public static void main(String[] args) {// TODO Auto-generated method stubScanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();init();for (int i = 0; i < m; i++) {int u = sc.nextInt() - 1;int v = sc.nextInt() - 1;list[u].add(v);}for (int i = 0; i < n; i++) {if (!vis[i]) {tarjan(i);}}System.out.println(Arrays.toString(num));}}
/** 6 8 1 2 1 3 2 4 3 4 3 5 4 1 4 6 5 6*/

双连通分量

双连通与强连通,最本质的差别就是前者适用于无向图中,而后者适用于有向图。至于两者的概念是一样的,就是图中有a点、b点,从a点可到达b点,同时从b点可到达a点。(若是有向图必须延方向到达。)

其中双连通分量可细分为:点-双连通分量,边-双连通分量。所谓点-双连通分量是指在一个无向图中两点间至少有两条路径,且路径中(不算头尾)的点不同。不同的点-双连通分量最多有一个公共点,这个点必定是“割点”。

边-双连通分量是指在一个无向图中两点间至少有两条路径,且路径中的边不同。边-双连通分量中一定没有桥。

  • 点-双连通图:一个连通的无向图内部没有割点,那么该图是点-双连通图。
  •         注意:孤立点,以及两点一边这两种图都是点-双连通的,因为它们都是内部无割点。

  • 边-双连通图:一个连通的无向图内部没有桥,那么该图就是边-双连通图。
  •         注意:孤立点是边-双连通的,但是两点一边不是边-双连通的。

所以可以看出判断双连通分量的条件:

判断一个图是不是点-双连通的只要看图中是否有割点。(比寻找割点多了个栈而已)

判断一个图是不是边-双连通的只要看图中是否有桥。

强联通分量与双连通分量相关推荐

  1. 强联通分量,双联通分量详解

    正题 强联通分量 我们开两个数组 l o w , d f n low,dfn low,dfn . d f n dfn dfn 表示 i i i 点的 d f s dfs dfs 序, l o w lo ...

  2. 强连通分量/点双连通分量/边双联通分量 总结

    前言 % 被某brz逼着问,觉得很有必要好好复习一下这 些 毒瘤东西. 定义 % 连通 如果有向图中的两点 uuu,vvv 间同时存在 uuu 到 vvv 的路径及 vvv 到 uuu 的路径,则称点 ...

  3. 关于强联通分量 的求法讨论

    这个讨论主要是关于 HA2006年最受欢迎的牛 的讨论 . 尽管这道题对于很多dalao来说都觉得是模板题,但是仍是值得思考的,因为我第一次写这道题的时候, 缩完点之后建图建错玄学跑dfs n^2做法 ...

  4. BZOJ 2140 稳定婚姻(强联通分量判环)【BZOJ修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2140 是 hydro 的 BZOJ ...

  5. [图论]强联通分量+缩点 Summer Holiday

    Summer Holiday Description 听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系 ...

  6. CodeForces 1213F (强联通分量分解+拓扑排序)

    传送门 •题意 给你两个数组 p,q ,分别存放 1~n 的某个全排列: 让你根据这两个数组构造一个字符串 S,要求: (1)$\forall i \in [1,n-1],S_{pi}\leq S _ ...

  7. P3387-【模板】缩点【tarjan,强联通分量,DAGdp】

    正题 评测记录: https://www.luogu.org/recordnew/lists?uid=52918&pid=P3387 大意 一个有向图.每个点有权值,但每个值只能取一次,每条边 ...

  8. Tarjan的强联通分量

    求强联通分量有很多种. <C++信息学奥赛一本通>  中讲过一个dfs求强联通分量的算法Kosdaraju,为了骗字数我就待会简单的说说.然而我们这篇文章的主体是Tarjan,所以我肯定说 ...

  9. POJ 2186 Popular Cows (强联通分量)

    链接 :http://poj.org/problem?id=2186 一个联通分量里的所有的牛满足任何一个被其他牛认为是红人.强联通缩点之后 只需要找到一个且只有一个联通分量且它的出度为0 答案就是这 ...

最新文章

  1. 手动将web项目的class文件打成jar包,手动打jar包,java -cvf,IDE打包底层指令
  2. 使用tab键分割的文章能快速转换成表格。( )_无需按空格键,就能将Word文字对齐,3种方法了解一下...
  3. chart.js 饼图显示百分比_Echarts饼图展示车站客流占比图
  4. 《LINUX下动态链接库的创建与应用》
  5. 蓝桥杯真题-连号区间数-枚举
  6. JAVA入门级教学之(浮点型数据类型)
  7. 【转载】失业的程序员(九):创业就是一场戏
  8. Cause: the class org.apache.tools.ant.taskdefs.optional.ANTLR was not found.
  9. 关于GetTickCount函数的用法
  10. 决策树识别MNIST数据集
  11. 嵌入式linux交叉开发环境,构建嵌入式Linux交叉开发环境
  12. 推荐一些游戏项目,直接起飞,不看后悔
  13. 数据库 | Redis 缓存雪崩解决方案
  14. DH坐标系的建立与DH表—机器人学
  15. 2021B站1024程序员节 网络攻防CTF
  16. 信号处理趣学D4——利用谐波叠加对周期方波进行逼近
  17. (Tiled官方文档翻译)第二节:四种图层的介绍
  18. 2 snippets vue 修改配置_vue-snippets: 支持 Vue 3 的语法高亮,代码格式化和代码提示的 Visual Studio Code 插件。...
  19. 设计模式 - 学习笔记 - 适配器模式AdapterPattern
  20. shell-awk命令详解

热门文章

  1. 有限域和离散对数问题(ECC椭圆曲线算法2)
  2. 深圳国际智能家居展览会
  3. Android:判断手机运营商
  4. html显示当前年份,js如何获取到当前年份 和当前的年份-1
  5. NAO机器人——运动控制(2)
  6. Enriching Local and Global Contexts for Temporal Action Localization ContextLoc论文阅读笔记
  7. c语言打印出水花数,四叶玫瑰数,五角星数等等的数字
  8. 第九届大唐杯省赛知识梳理-5G网络技术(10%)
  9. 详解vue生命周期(重点!!)
  10. Java——你知道long和Long有什么区别吗?