给定一个有向图 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 标准库系列之assert.h

    先简单介绍一下<assert.h>头文件,该头文件的目的便是提供一个宏assert的定义,即可以在程序必要的地方使用其进行断言处理:断言在程序中的作用是当在调试模式下时,若程序给出的前提条 ...

  2. 【iOS Instrument性能优化集】

    iOS Instrument性能优化集 1.UIImage缓存取舍 在项目代码中看到大量使用如下代码: UIImage使用 在Main Thread中发现不同动画场景中Image IO 开销和耗时所占 ...

  3. html5吹牛扯淡篇,闲话内容。

    09年提出对媒体查询的草案,到今天的广泛运用,w3c带我们走进了个性化定制的殿堂.这些之所以会被认可会被写进世界级标准,因为他越来越适应广大用户的需求,需求就像一条锁链带动或者牵引整个互联网开发工作. ...

  4. wpf 触发器理解

    (1)属性触发器:其对应的类是Trigger.它在特定关联属性发生变化时被触发.一个属性的更改会在另一个属性中触发即时或动态更改. (2)数据触发器:其对应的类是DataTrigger.它在特定的CL ...

  5. iOS之 状态栏字体颜色的设置

    前一段时间接手一个项目后,熟悉的过程中发现了不少问题,其中有一个就是关于状态栏的问题. 我们都知道:状态栏字体颜色在不同界面不一样的,原因是系统设置的时候把状态栏的字体颜色的界面控制器设置的yes. ...

  6. hihocoder挑战赛13A

    #1191 : 小W与网格 描述 给定一个n*m的网格,左上角(1, 1),右下角(n, m). 小w在(i, j),他会从"上左下右"四个方向中选定两个不同但正交的方向,然后他只 ...

  7. 【转】Java提高篇(三四)-----fail-fast机制

    转自:http://blog.csdn.net/chenssy/article/details/38151189  在JDK的Collection中我们时常会看到类似于这样的话:         例如 ...

  8. pair的使用

    #include<iostream> #include<cmath> #include<cstdio> #include<algorithm> #inc ...

  9. 基于redis的点赞功能设计

    前言 点赞其实是一个很有意思的功能.基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回m ...

  10. Android中ListView的几种常见的优化方法

    Android中的ListView应该算是布局中几种最常用的组件之一了,使用也十分方便,下面将介绍ListView几种比较常见的优化方法: 首先我们给出一个没有任何优化的Listview的Adapte ...