算法7-11:强连通分量

首先介绍的是一个强大的连接。顶点之间的紧密联系是假设v达到w,然后,w你可以达到v。顶点之间的强连接就表示顶点之间能够双向到达,也就是说两个顶点在一个回路上。

介绍了强连接。那什么是强连接部件呢?强连接部件就是可以相互到达的全部顶点的集合。一个图中可能会有多个强连接。

强连接在离散数学中属于等价关系,也就是说它具有反射性,相反性。传递性。

应用

强连接在生物学中有所应用。食物链就是一个样例。下图展示了一个非常小的食物链。

在食物链中,强连接部件表示在同一个部件中的生物共享同样的能量流。

强连接部件在软件project中也有应用。一个软件中有很多模块。假设将软件中的模块看成顶点,将模块之间的依赖关系看成图论中的边。那么这就是一个有向图。在同一个强连接部件中的模块之间耦合度是比較高的。依照软件设计原则,耦合度高的模块往往要放在一个包中。

所以,强连接部件能够检測模块之间的耦合度。能够软件结构的优化起到指导作用。

算法

为了计算出一个有向图中有多少强连接部件,世界上有一种名叫Kosaraj Sharir算法,这样的算法很easy。可是比較神奇,一般的人无法直观地看出为什么这样算可以得到正确的结果。

这个算法的分为两个阶段。

第一个阶段就是对有向图的反图进行拓扑排序。注意是反图。第二个阶段就像连接部件算法一样,依照排序结果,对未曾訪问过的节点运行DFS。

有了这种思路。那么代码就立即出来了:

public class StrongComponent {
    private boolean[] visited;
    private int[] id;
    private int count;

    public StrongComponent(Digraph G) {
        visited = new boolean[G.V()];
        id = new int[G.V()];

        // 计算反图的拓扑排序
        Digraph R = G.reverse();
        Iterable<Integer> sort = new DepthFirstOrder(R).sort();

        // 对每一个未曾訪问过的顶点运行dfs
        for (int v : sort) {
            if (!visited[v]) {
                dfs(G, v);
                count++;
            }
        }
    }

    public int count() {
        return count;
    }

    public boolean stronglyConnected(int v, int w) {
        return id[v] == id[w];
    }

    public int id(int v) {
        return id[v];
    }

    private void dfs(Digraph G, int v) {
        visited[v] = true;
        id[v] = count;
        for (int w : G.adj(v)) {
            if (!visited[w]) {
                dfs(G, w);
            }
        }
    }
}

版权声明:本文博主原创文章。博客,未经同意不得转载。

时间: 2024-08-19 09:13:06

算法7-11:强连通分量的相关文章

poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)

1 /* 2 题目大意:有N个cows, M个关系 3 a->b 表示 a认为b popular:如果还有b->c, 那么就会有a->c 4 问最终有多少个cows被其他所有cows认为是popular! 5 6 思路:强连通分量中每两个节点都是可达的! 通过分解得到最后一个连通分量A, 7 如果将所有的强连通分量看成一个大的节点,那么A一定是孩子节点(因为我们先 8 完成的是父亲节点的强连通分量)! 最后如果其他的强连通分量都可以指向A,那么 9 A中的每一个cow都会被其他cows所

『Tarjan算法 有向图的强连通分量』

有向图的强连通分量 定义:在有向图\(G\)中,如果两个顶点\(v_i,v_j\)间\((v_i>v_j)\)有一条从\(v_i\)到\(v_j\)的有向路径,同时还有一条从\(v_j\)到\(v_i\)的有向路径,则称两个顶点强连通(strongly connected).如果有向图\(G\)的每两个顶点都强连通,称\(G\)是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 万能的Tarjan算法也可以帮助我们求解有向图的强

Tarjan算法求有向图强连通分量并缩点

// Tarjan算法求有向图强连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; const int N = 100010, M = 1000010; // int ver[M], Next[M], head[N],

算法模板——Tarjan强连通分量

功能:输入一个N个点,M条单向边的有向图,求出此图全部的强连通分量 原理:tarjan算法(百度百科传送门),大致思想是时间戳与最近可追溯点 这个玩意不仅仅是求强连通分量那么简单,而且对于一个有环的有向图可以有效的进行缩点(每个强连通分量缩成一个点),构成一个新的拓扑图(如BZOJ上Apio2009的那个ATM)(PS:注意考虑有些图中不能通过任意一个单独的点到达全部节点,所以不要以为直接tarjan(1)就了事了,还要来个for循环,不过实际上复杂度还是O(M),因为遍历过程中事实上每个边还是

图论算法之(强连通分量&lt;Kosaraju&gt;)

强连通分量算法有3个之多,现在介绍这种名字叫做kosaraju算法. 这个算法基于两个事实,1.原图G与逆置图GT拥有相同的强连通分量,这肯定是正确的 2.任意一个子节点存放皆后于父节点,也就是说所有只有当所有子节点都入栈了,父节点才入栈 这种在递归调用之后将顶点入队列的方式叫逆后续排序(reverse post),在无环图中这种排序方式就是拓扑排序. 简要证明: 1. 第一次DFS有向图G时,最后记录下的节点必为最后一棵生成树的根节点. 证明:假设最后记录下节点不是树根,则必存在一节点为树根,

Tarjan算法【强连通分量】

转自:byvoid:有向图强连通分量的Tarjan算法 Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的所有节点是否为一个强连通分量. 有两个概念:1.时间戳,2.追溯值 时间戳是dfs遍历节点的次序. 定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的栈中节点最小的次序号.由定义可以得出: 1 Low(u)=min{ 2 DFN(u), // 自己的

图之强连通、强连通图、强连通分量 Tarjan算法

强连通分量 简介 在阅读下列内容之前,请务必了解图论基础部分. 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图. 这里想要介绍的是如何来求强连通分量. Tarjan 算法 Robert E. Tarjan (1948~) 美国人. Tarjan 发明了很多算法结构.光 Tarjan 算法就有很多,比如求各种联通分量的 Tarjan 算法,求 LCA(Lowest Comm

有向图的强连通分量(tarjan算法)

强连通分量 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 考虑强连通分量C,设其中第一个被发现的点为x,则,C中其他的点都是x的后代.我们希望在x访问完成时立即输出C(可以同时记录C,输出代表

TarJan 算法求解有向连通图强连通分量

[有向图强连通分量] 在有向图G中,如果两个 顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. 大体来说有3中算法Kosaraju,Trajan,Gabow这三种!后续文章中将相继