给定一个有向图 G = (V, E) ,对于任意一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的,则说明该图 G 是强连通的(Strongly Connected)。如下图中,任意两个顶点都是互相可达的。

对于无向图,判断图是否是强连通的,可以直接使用深度优先搜索(DFS)或广度优先搜索(BFS),从任意一个顶点出发,如果遍历的结果包含所有的顶点,则说明图是强连通的。

而对于有向图,则不能使用 DFS 或 BFS 进行直接遍历来判断。如下图中,如果从顶点 0 开始遍历则可判断是强连通的,而如果从其它顶点开始遍历则无法抵达所有节点。

那么,该如何判断有向图的强连通性呢?

实际上,解决该问题的较好的方式就是使用强连通分支算法(SCC:Strongly Connected Components),可以在 O(V+E) 时间内找到所有的 SCC。如果 SCC 的数量是 1,则说明整个图是强连通的。

有向图 G = (V, E) 的一个强连通分支是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的。

实现 SCC 的一种算法就是 Kosaraju 算法。Kosaraju 算法基于深度优先搜索(DFS),并对图进行两次 DFS 遍历,算法步骤如下:

  1. 初始化设置所有的顶点为未访问的;
  2. 从任意顶点 v 开始进行 DFS 遍历,如果遍历结果没有访问到所有顶点,则说明图不是强连通的;
  3. 置换整个图(Reverse Graph);
  4. 设置置换后的图中的所有顶点为未访问过的;
  5. 从与步骤 2 中相同的顶点 v 开始做 DFS 遍历,如果遍历没有访问到所有顶点,则说明图不是强连通的,否则说明图是强连通的。

Kosaraju 算法的思想就是,如果从顶点 v 可以抵达所有顶点,并且所有顶点都可以抵达 v,则说明图是强连通的。

 using System;
using System.Collections.Generic;
using System.Linq; namespace GraphAlgorithmTesting
{
class Program
{
static void Main(string[] args)
{
Graph g = new Graph();
g.AddEdge(, , );
g.AddEdge(, , );
g.AddEdge(, , );
g.AddEdge(, , );
g.AddEdge(, , );
g.AddEdge(, , ); Console.WriteLine();
Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
Console.WriteLine(); Console.WriteLine("Is graph strongly connected: {0}", g.Kosaraju()); Console.ReadKey();
} class Edge
{
public Edge(int begin, int end, int weight)
{
this.Begin = begin;
this.End = end;
this.Weight = weight;
} public int Begin { get; private set; }
public int End { get; private set; }
public int Weight { get; private set; } public override string ToString()
{
return string.Format(
"Begin[{0}], End[{1}], Weight[{2}]",
Begin, End, Weight);
}
} class Graph
{
private Dictionary<int, List<Edge>> _adjacentEdges
= new Dictionary<int, List<Edge>>(); public Graph(int vertexCount)
{
this.VertexCount = vertexCount;
} public int VertexCount { get; private set; } public IEnumerable<int> Vertices { get { return _adjacentEdges.Keys; } } public IEnumerable<Edge> Edges
{
get { return _adjacentEdges.Values.SelectMany(e => e); }
} public int EdgeCount { get { return this.Edges.Count(); } } public void AddEdge(int begin, int end, int weight)
{
if (!_adjacentEdges.ContainsKey(begin))
{
var edges = new List<Edge>();
_adjacentEdges.Add(begin, edges);
} _adjacentEdges[begin].Add(new Edge(begin, end, weight));
} public bool Kosaraju()
{
// Step 1: Mark all the vertices as not visited (For first DFS)
bool[] visited = new bool[VertexCount];
for (int i = ; i < visited.Length; i++)
visited[i] = false; // Step 2: Do DFS traversal starting from first vertex.
DFS(, visited); // If DFS traversal doesn’t visit all vertices, then return false.
for (int i = ; i < VertexCount; i++)
if (visited[i] == false)
return false; // Step 3: Create a reversed graph
Graph reversedGraph = Transpose(); // Step 4: Mark all the vertices as not visited (For second DFS)
for (int i = ; i < visited.Length; i++)
visited[i] = false; // Step 5: Do DFS for reversed graph starting from first vertex.
// Staring Vertex must be same starting point of first DFS
reversedGraph.DFS(, visited); // If all vertices are not visited in second DFS, then
// return false
for (int i = ; i < VertexCount; i++)
if (visited[i] == false)
return false; return true;
} void DFS(int v, bool[] visited)
{
visited[v] = true; if (_adjacentEdges.ContainsKey(v))
{
foreach (var edge in _adjacentEdges[v])
{
if (!visited[edge.End])
DFS(edge.End, visited);
}
}
} Graph Transpose()
{
Graph g = new Graph(this.VertexCount); foreach (var edge in this.Edges)
{
g.AddEdge(edge.End, edge.Begin, edge.Weight);
} return g;
}
}
}
}

参考资料

本篇文章《Kosaraju 算法检测有向图的强连通性》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。

Kosaraju 算法检测有向图的强连通性的更多相关文章

  1. 【模板】Tarjan算法与有向图的强连通性

    概念 流图 给定一个有向图G= (V,E),若存在r∈V满足,满足从r出发能够到达V中所有的点,则称G是一个流图,记为(G,r),其中r是流图的源点. 流图的搜索树 在一个流图(G,r)上从r出发,进 ...

  2. 强联通分量之kosaraju算法

    首先定义:强联通分量是有向图G=(V, E)的最大结点集合,满足该集合中的任意一对结点v和u,路径vu和uv同时存在. kosaraju算法用来寻找强联通分量.对于图G,它首先随便找个结点dfs,求出 ...

  3. 图解:有向环、拓扑排序与Kosaraju算法

    图算法第三篇 图解:有向环.拓扑排序与Kosaraju算法 首先来看一下今天的内容大纲,内容非常多,主要是对算法思路与来源的讲解,图文并茂,希望对你有帮助~ 1.有向图的概念和表示 概念 有向图与上一 ...

  4. 7-6-有向图强连通分量的Kosaraju算法-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

    课本源码部分 第7章  图 - 有向图强连通分量的Kosaraju算法 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接☛☛☛ <数据结构-C语言版>(严 ...

  5. hdu2767 Proving Equivalences,有向图强联通,Kosaraju算法

    点击打开链接 有向图强联通,Kosaraju算法 缩点后分别入度和出度为0的点的个数 answer = max(a, b); scc_cnt = 1; answer = 0 #include<c ...

  6. Kosaraju算法---强联通分量

    1.基础知识 所需结构:原图.反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边).标记数组(标记是否遍历过).一个栈(或记录顶点离开时间的数组).      算法描叙: :对 ...

  7. 有向图强连通分量的Tarjan算法和Kosaraju算法

    [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...

  8. 图论-求有向图的强连通分量(Kosaraju算法)

    求有向图的强连通分量     Kosaraju算法可以求出有向图中的强连通分量个数,并且对分属于不同强连通分量的点进行标记. (1) 第一次对图G进行DFS遍历,并在遍历过程中,记录每一个点的退出顺序 ...

  9. (转)求有向图的强连通分量个数(kosaraju算法)

    有向图的连通分量的求解思路 kosaraju算法 逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下 原博客https://www.cnblogs.com/nullzx/p/6437926 ...

随机推荐

  1. 读书笔记《深度探索c++对象模型》 概述

    <深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...

  2. Oracle REGEXP_SUBSTR()

    REGEXP_SUBSTR函数格式如下: function REGEXP_SUBSTR(String, pattern, position, occurrence, modifier)       _ ...

  3. list for循环中删除元素

    Iterator.remove() is safe, you can use it like this: List<String> list = new ArrayList<> ...

  4. MVVM页面跳转 技巧性标记

    刚学MVVM 百度了很多概念性的东西 也参考了网上的例子 基本有了了解 但是我发现 我做了一个登录页面以后 我跳转咋办呢? VM里面咋做跳转? 问了一下其他的群友得到了一些启发.感谢“上海*松” 我仅 ...

  5. 3 3Sum closest_Leetcode

    Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...

  6. Python-断言

    断言: assert这个关键字称之为断言,当这个关键字后面的条件为假的时候,程序自动崩溃并抛出AssertionError的异常 例子: >>>assert 3 < 4 Tra ...

  7. 转:工具类之SpannableStringUtils(相信你会爱上它)

    这个工具类真是构思了良久才设计出来,采用了建造者模式,然后你们就可以用链式调用了,talk is cheap, let me show the demo. demo code 有没有心动一下哈,下面就 ...

  8. CompiledEffect Direct3D9 Sample fxc.exe

  9. Dictionary Learning(字典学习、稀疏表示以及其他)

    第一部分 字典学习以及稀疏表示的概要 字典学习(Dictionary Learning)和稀疏表示(Sparse Representation)在学术界的正式称谓应该是稀疏字典学习(Sparse Di ...

  10. VS2015 调试时 编辑并继续不可用

    最近在项目中遇到一次调试时 编辑并继续不可用.结合网上说的工具->设置->调试->常规下的一些操作,到后来还是不可用,最后把项目的解决方案平台改成Mixed Platform ,之后 ...