算法7-11:强连接部件

首先介绍什么是强连接。顶点之间的强连接就是如果v能到达w,那么w也能到达v。顶点之间的强连接就表示顶点之间可以双向到达,也就是说两个顶点在一个回路上。

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

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

应用

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

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

强连接部件在软件工程中也有应用。一个软件中有许多模块,如果将软件中的模块看成顶点,将模块之间的依赖关系看成图论中的边,那么这就是一个有向图。在同一个强连接部件中的模块之间耦合度是比较高的。按照软件设计原则,耦合度高的模块往往要放在一个包中。所以,强连接部件可以检测模块之间的耦合度,可以软件结构的优化起到指导作用。

算法

为了计算出一个有向图中有多少强连接部件,世界上有一种名叫Kosaraj Sharir算法,这种算法非常简单,但是比较神秘,一般的人无法直观地看出为什么这样算能够得到正确的结果。

这个算法的分为两个阶段。第一个阶段就是对有向图的反图进行拓扑排序,注意是反图。第二个阶段就像连接部件算法一样,按照排序结果,对未曾访问过的节点执行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);
            }
        }
    }
}

算法7-11:强连接部件

时间: 2024-10-19 00:00:58

算法7-11:强连接部件的相关文章

算法7-5:连接部件

同学们一定用过Windows中的画图吧.那么画图中的油漆桶功能是如何实现的呢? 这个问题可以通过DFS深度优先搜索解决. 目标 我们要实现的目标是在常数的时间内判断某两个节点是否连接. 前面章节中介绍了并查集算法,并查集确实可以解决这个问题.我们今天来介绍另外一种办法,那就是DFS深搜. 为了解决这个问题专门建立一个对象,对象的轮廓如下: public class ConnectedComponnent { public ConnectedComponnent(Graph G) { } // 判

算法实验11:还是畅通工程(最小生成树 kruscal prim)

算法实验11:还是畅通工程 Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小.请计算最小的公路总长度. Input 测试输入包含若干测试用例.每个测试用例的第1行给出村庄数目N ( < 100 ):随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离.为简单起

Horspool 算法C++11实现(支持中英文混合搜索)

摘要: 本文给出一个horspool算法的实现,展示一个使用示例,并向介绍一个非常好用的UTF8字符转码项目,给出一个简单的测试报告等. 算法实现: #include <iostream> #include <unordered_map> //#include <codecvt> #include <fstream> #include <iterator> #include <sstream> #include <bitset&

Qt5信号与槽C++11风格连接简介

最近在论坛上看到了这个方面的问题,详见这里. 随后浅浅地学习了一下子,看到了Qt官方论坛上给出的说明,觉得C++11的functional连接方法还是比Qt4既有的宏连接方法有很大不同. 官方论坛的文档:http://doc.qt.io/qt-5/signalsandslots-syntaxes.html 1.实验代码 我们在一个简单的Dialog中,安排如下几个信号与槽: class SSTest : public QDialog { //... signals: void sgn_test1

#11 硬连接与软链接与RAID与LVM2

两种特殊文件: 设备文件: mknod 符号链接文件: 链接:就是访问一个文件的不同路径: 硬连接: 数据块指针指向同一个数据块的文件: 不能跨文件系统创建硬连接: 目录文件不能创建硬连接: 每次创建硬连接都会增加indoe的引用计数 符号链接(软链接): 用于储存被链接文件的路径的文件: 可以跨文件系统创建: 也可以对目录创建: 每次都必粗进行两组路径的查找: ln命令: ln [option...] src_flie link_file ln - make links between fil

计算机网络(11)-----TCP连接的建立和释放

TCP连接的建立和释放 概述 TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程,运输连接有三个阶段:连接建立,数据传送和连接释放. TCP连接的建立 如图所示,假定A主机是客户端程序,B主机是服务端程序.最初两端的TCP进程都是出于CLOSED(关闭)状态. (1)B的TCP服务器进程先创建传输控制块TCB(transmission Control Block),准备接受客户进程的连接请求.然后服务器就进入LISTEN(监听)状态,等待客户端的连接请求. (2)A的TCP客户进程

常见排序算法导读(11)[桶排序]

上一节讲了基数排序(Radix Sort),这一节介绍桶排序(Bucket Sort or Bin Sort).和基数排序一样,桶排序也是一种分布式排序. 桶排序(Bucket Sort)的基本思想 将待排对象序列按照一定hash算法分发到N个桶中 对每一个桶的待排对象进行排序 从头到尾遍历N个桶,收集所有非空的桶里的有序对象(子序列)组成一个统一的有序对象序列 在每一个桶中,如果采用链式存储的话,1.和2.可以合并在一起操作,也就是在分发的过程中保证每一个桶的对象桶内有序. 例如: 设有5个桶

微软数据挖掘算法:Microsoft 线性回归分析算法(11)

前言 此篇为微软系列挖掘算法的最后一篇了,完整该篇之后,微软在商业智能这块提供的一系列挖掘算法我们就算总结完成了,在此系列中涵盖了微软在商业智能(BI)模块系统所能提供的所有挖掘算法,当然此框架完全可以自己扩充,可以自定义挖掘算法,不过目前此系列中还不涉及,只涉及微软提供的算法,当然这些算法已经基本涵盖大部分的商业数据挖掘的应用场景,也就是说熟练了这些算法大部分的应用场景都能游刃有余的解决,每篇算法总结包含:算法原理.算法特点.应用场景以及具体的操作详细步骤.为了方便阅读,我还特定整理一篇目录:

【初级算法】11.旋转图像

题目: 给定一个 n × n 的二维矩阵表示一个图像. 将图像顺时针旋转 90 度. 说明: 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵.请不要使用另一个矩阵来旋转图像. 示例 1: 给定 matrix = [ [1,2,3], [4,5,6], [7,8,9] ], 原地旋转输入矩阵,使其变为: [ [7,4,1], [8,5,2], [9,6,3] ] 示例 2: 给定 matrix = [ [ 5, 1, 9,11], [ 2, 4, 8,10], [13, 3, 6, 7