【Algorithms IV】求解强连通分量 Kosaraju算法

【Algorithms IV】求解强连通分量 Kosaraju算法


Kosaraju
算法(也被称为Kosaraju–Sharir算法)是一个在线性时间内寻找一个有向图中的强连通分量的算法。

这个拗口的名字来自他的作者,但是查不到他的生平。应该是个印度人。

求解问题:要求有向图中的强连通分量的个数/划分

算法步骤:

即:

对输入G, 反转边获得逆向图GR

    用DFS算法对图遍历得到reversePost序列(遍历图后push 到一个stack里,之后stack逆序弹出)

依次对reversePost的未访问节点进行dfs, 一次dfs访问过的所有节点在一个强联通分量里。

当图是使用邻接表形式组建的,Kosaraju算法需要对整张图进行了两次的完整的访问,每次访问与顶点数 V和边数 E之和 V+E成正比,所以O(V+E)内访问完成。

算法用到的定理:

 一个图的反向图和原图具有一样的强连通分量。

一个图的reversePost的压入顺序是它的拓扑排序当且仅当它是DAG。

代码 (in JAVA):

KosarajuSCC.java
public class KosarajuSCC {
    private boolean[] marked; // reached vertices
    private int[] id; // component identifiers
    private int count; // number of strong components

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

        DepthFirstOrder order = new DepthFirstOrder(G.reverse());
        for (int s : order.reversePost()) {
            if (!marked[s]) {
                dfs(G, s);
                count++;
            }
        }
    }

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

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

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

    public int count() {
        return count;
    }

    public static void main(String args[]) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            int N = in.nextInt();
            Digraph G = new Digraph(N);
            int E = in.nextInt();
            for (int i = 0; i < E; i++) {
                int p = in.nextInt();
                int q = in.nextInt();
                G.addEdge(p, q);
            }
            KosarajuSCC kj = new KosarajuSCC(G);
            log("" + kj.count());
        }
    }

    private static void log(String count2) {
        System.out.println(count2);
    }
}

References

http://blog.csdn.net/dm_vincent/article/details/8554244

https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/KosarajuSharirSCC.java.html

时间: 2024-10-16 11:07:15

【Algorithms IV】求解强连通分量 Kosaraju算法的相关文章

CSU 1612: Destroy Tunnels 强连通分量 Kosaraju算法

链接 :  http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1612 题意: 给一个矩阵A 大小N*N, B = A^1 + A^2 + A^3 + .... A^n , B中是否存在非0项. 题目可以转化为 N个点 编号为1-n, 对于任意点v,经过一些任意的步长到达u (u为所有点集的任意一个).离散数学里有图的矩阵相关知识 A^k代表了矩阵中从i到j的步长为k的方法数. 题目就是求整个图是否强连通. 学习了 Kosaraju算法 可以轻

图的强连通分量-Kosaraju算法

输入一个有向图,计算每个节点所在强连通分量的编号,输出强连通分量的个数 1 #include<iostream> 2 #include<cstring> 3 #include<vector> 4 using namespace std; 5 const int maxn=1024; 6 struct Edge{ 7 int go,next; 8 }; 9 int vis[maxn],count=0,book[maxn]; 10 vector<Edge> G,

POJ2186 Popular Cows 【强连通分量Kosaraju】

Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23445   Accepted: 9605 Description Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M &l

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

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

求有向图的强连通分量的算法

下面是求有向图的强连通分量的算法的代码: import java.util.Scanner; class Qiufenliang//定义求强连通分量的类 { String lu="";//定义的一个字符型变量,记录强连通分量的路径 public static int s=0; public void qiu(int a[][],int l)//定义函数,参数a为二维数组,参数l为数组的维数 { int t=0;//定义int型变量,进行数量的统计 for(int i=1;i<l;

HDU 1269 强连通分量tarjan算法

迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6655    Accepted Submission(s): 2973 Problem Description 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房

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

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

强连通分量-----Kosaraju

芝士: 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量. 如图中1,2,3,4是一个强连通分量. Kosaraju算法: 如果这是一个无向图,那么从一个节点出发,深搜得到的所有节点都是连通的. 但这是一个有向图,起始节点的不同会导致结果的不同,举个栗子,从5搜

强连通分量Kosaraju、Tarjan【模板】

强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通.如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量. 把一个图变为一个强连通图需要添加边数:先求出原图的强连通分量,缩点后变为有向无环图,计算新图入度为0的点的个数SumIn和出度为0的点的个数SumOut,答案就是max(SumIn,SumOut). Kosaraju算法: 1.对原图进行第一遍深度优先遍