Kosaraju算法---强联通分量
1、基础知识
所需结构:原图、反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边)、标记数组(标记是否遍历过)、一个栈(或记录顶点离开时间的数组)。
算法描叙:
步骤1:对原图进行深度优先遍历,记录每个顶点的离开时间。
步骤2:选择具有最晚离开时间的顶点,对反向图进行深度优先遍历,并标记能够遍历到的顶点,这些顶点构成一个强连通分量。
步骤3:如果还有顶点没有遍历过,则继续进行步骤2,否则算法结束。
在dfs(bfs)中,一个结点的开始访问时间指的是遍历时首次遇到该结点的时间,而该结点的结束访问时间则指的是将其所有邻接结点均访问完的时间。
下面结合实例说明Kosaraju算法的基本策略。图1给出了一个有向图G。
Step1:假设从DFS在遍历时按照字母顺序进行,从4开始搜索得到以下搜索序列:[4,[5,[7,[6,[8,8],6],7],5],4] [1,[2,[3,3],2],1] 在遍历序列中每一个结点出现了两次,其中第一次出现的时间为该结点的开始访问时间,第二次出现的时间为该结点的结束访问时间。
根据结点结束访问时间的定义,在某一次调用DFS_SEARCH中,显然遍历时越早遇到的结点,相对结束访问时间也就越晚,因此在这一次调用DFS_SEARCH内结点结束的时间递减顺序与结点首次访问顺序一致。而对于不同次调用DFS_SEARCH,调用越晚其相对结点结束的时间也就越晚。根据上述分析,我们可以在第一次DFS遍历时一次得到内结点结束的时间的递减顺序。
1)该图得到一个搜索树林共两个搜索树,一个以4为根(4能到达的所有点),一个以1为根(1能到达的所有点)。
2)4能到的所有点在搜索序列里挨一起,4不能到的点形成的搜索序列肯定在其右边。
3)搜索序列的左右括号是成对出现的,满足括号匹配的原则。某个节点两端括住的节点都是他能到达的所有结点。最先开始访问的节点(左括号),肯定也是其搜在 子树里面最后一个访问的节点(右括号)。
Step2:对图进行反向,再从1(4)[先1后4]点进行dfs,相当于在反向前的原图中求出所有能到达1(4)的点。
Step3:按结束时间从大到小进行搜索。我们看搜索序列,最后一个点肯定是第一遍深搜时得到的最后一棵树的根r。从它开始深搜,相当于求出所有能达到树根r的点。这样得到的搜索子树肯定是一个强联通分量。
图的存储表示形式:邻接矩阵[1,2标记原图和逆图的边]、邻接表。
Kosaraju算法的显著特征是:第一,引用了有向图的逆图;为了突出回向边,而对图进行转置,然后对转置的图按照之前得到的顶点序列进行DFS调用。第二,需要 对图进行两次DFS(一次在逆图上,一次在原图上)。而且这个算法依赖于一个事实:一个有向图的强连通分量与其逆图是一样的。由于算法的时间取决于两次DFS,因 此时间复杂度,对于稀疏图是O(V+E),对于稠密图是O(V²),可见这是一个线性算法。Kosaraju的结论是,在第二次DFS中,同一棵搜索树上的结点属于一个强连通分量。
与Tarjan算法的比较
在实际的测试中,时间:Tarjan算法的运行效率也比Kosaraju算法高30%左右。空间:Tarjan算法虽然比Kosaraju算法多用两个一维数组,但Kosaraju算法比Tarjan算法 多浪费建立一个反向图的空间,所以总体来说在空间复杂度上Tarjan比Kosaraju占优势。
隐藏性质:在第二次深搜选择树的顺序,若把求出来的每个强连通分量收缩成一个点 ,并且用求出每个强连通分量的顺序来标记收缩后的节点,那么这个顺序其实就是强连通分量收缩成点后形成的有向无环图的拓扑序列。
2、参考代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXL 100 /*图的邻接表定义*/
typedef struct edge_node{ //边NODE
int key;
struct edge_node *next;
}ENode;
typedef struct{ //顶点
char vertex;
ENode *firstedge;
}VNode;
typedef VNode VList[MAXL]; //顶点表
typedef struct{ //图
// int n,e;
VList vlist;
}ALGraph;
ALGraph *ALG=(ALGraph *)malloc(sizeof(ALGraph)); //原图邻接表
ALGraph *reverse_ALG=(ALGraph *)malloc(sizeof(ALGraph)); //逆图邻接表
int n,e; //两表共用 int vis[MAXL]; int num_scc;
int scc[MAXL]; int cnt;
int ord[MAXL]; void Creat_ALGraph(void) //建图[邻接表和逆邻接表]
{
int i,j;
char ch1,ch2;
ENode *ptr=(ENode *)malloc(sizeof(ENode)); scanf("%d,%d",&n,&e);
getchar(); for(i=;i<n;i++)
{
scanf("%c",&ALG->vlist[i].vertex);
getchar();
ALG->vlist[i].firstedge=NULL; reverse_ALG->vlist[i].vertex=ALG->vlist[i].vertex; //逆表
reverse_ALG->vlist[i].firstedge=NULL;
}
for(int k=;k<e;k++)
{
scanf("%c,%c",&ch1,&ch2);
getchar(); for(i=;ch1!=ALG->vlist[i].vertex;i++);
for(j=;ch2!=ALG->vlist[j].vertex;j++); ptr=(ENode *)malloc(sizeof(ENode));
ptr->key=j;
ptr->next=ALG->vlist[i].firstedge;
ALG->vlist[i].firstedge=ptr; ptr=(ENode *)malloc(sizeof(ENode)); //逆表
ptr->key=i;
ptr->next=reverse_ALG->vlist[j].firstedge;
reverse_ALG->vlist[j].firstedge=ptr;
}
} void init_kosaraju(void)
{
num_scc=;
cnt=;
for(int i=;i<n;i++)
{
vis[i]=;
scc[i]=-;
ord[i]=-;
}
} /*****************Kosaraju算法******************/
void orig_DFS(int u)
{
int son;
ENode *ptr=(ENode *)malloc(sizeof(ENode)); vis[u]=; //标记+遍历+入栈
ptr=ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
son=ptr->key;
if(!vis[son])
orig_DFS(son);
ptr=ptr->next;
}
ord[cnt++]=u;
} void reverse_DFS(int u)
{
int par;
ENode *ptr=(ENode *)malloc(sizeof(ENode)); scc[u]=num_scc; //归类+标记+遍历
vis[u]=;
ptr=reverse_ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
par=ptr->key;
if(!vis[par])
reverse_DFS(par);
ptr=ptr->next;
}
} void SCC_Kosaraju()
{
int i; for(i=;i<n;i++)
if(!vis[i])
orig_DFS(i); memset(vis,,sizeof(vis)); for(i=n-;i>=;i--)
if(!vis[ord[i]])
{
num_scc++;
reverse_DFS(ord[i]);
}
}
/*********************************************/ int main(void)
{
Creat_ALGraph(); init_kosaraju(); SCC_Kosaraju(); printf("%d\n",num_scc); //scc输出
for(int cn=;cn<=num_scc;cn++)
{
for(int j=;j<n;j++)
if(scc[j] == cn)
printf("%c ",ALG->vlist[j].vertex); //ALG、reverse_ALG均可
printf("\n");
} return ;
}
Kosaraju算法---强联通分量的更多相关文章
- Tarjan算法---强联通分量
1.基础知识 在有向图G,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子 ...
- POJ 2186 Popular cows(Kosaraju+强联通分量模板)
题目链接:http://poj.org/problem?id=2186 题目大意:给定N头牛和M个有序对(A,B),(A,B)表示A牛认为B牛是红人,该关系具有传递性,如果牛A认为牛B是红人,牛B认为 ...
- 强联通分量之kosaraju算法
首先定义:强联通分量是有向图G=(V, E)的最大结点集合,满足该集合中的任意一对结点v和u,路径vu和uv同时存在. kosaraju算法用来寻找强联通分量.对于图G,它首先随便找个结点dfs,求出 ...
- 【强联通图 | 强联通分量】HDU 1269 迷宫城堡 【Kosaraju或Tarjan算法】
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明 ...
- POJ 2186-Popular Cows (图论-强联通分量Korasaju算法)
题目链接:http://poj.org/problem?id=2186 题目大意:有n头牛和m对关系, 每一对关系有两个数(a, b)代表a牛认为b牛是“受欢迎”的,且这种关系具有传递性, 如果a牛认 ...
- 强联通分量-tarjan算法
定义:在一张有向图中,两个点可以相互到达,则称这两个点强连通:一张有向图上任意两个点可以相互到达,则称这张图为强连通图:非强连通图有极大的强连通子图,成为强联通分量. 如图,{1},{6}分别是一个强 ...
- 强联通分量(tarjan算法+算法简介)
题目描述 对于一个有向图顶点的子集S,如果在S内任取两个顶点u和v,都能找到一条从u到v的路径,那么就称S是强连通的.如果在强连通的顶点集合S中加入其他任意顶点集合后,它都不再是强连通的,那么就称S ...
- Tarjan 算法求割点、 割边、 强联通分量
Tarjan算法是一个基于dfs的搜索算法, 可以在O(N+M)的复杂度内求出图的割点.割边和强联通分量等信息. https://www.cnblogs.com/shadowland/p/587225 ...
- 【POJ 1236 Network of Schools】强联通分量问题 Tarjan算法,缩点
题目链接:http://poj.org/problem?id=1236 题意:给定一个表示n所学校网络连通关系的有向图.现要通过网络分发软件,规则是:若顶点u,v存在通路,发给u,则v可以通过网络从u ...
随机推荐
- C++ const && define
本文记录了C++中的const关键字的内容,分为3个部分,const和define的区别,const的作用,const的使用. const和define的区别 const的作用 const用于定义常量 ...
- 敏捷数据科学:用Hadoop创建数据分析应用
敏捷数据科学:用Hadoop创建数据分析应用(数据分析最佳实践入门敏捷大数据首作分步骤|全流程演示思路.工具与方法) [美]Russell Jurney(拉塞尔·朱尔尼) 著 冯文中 朱洪波 译 ...
- 《轻量级Java Web整合开发入门SSH》 - 快速理解Java框架的又一积木
学习JAVA不难,难的是没有多余的时间给你仔细学习. 伴随着项目的不断跟进,责任重于泰山,必须快速提升. 我不能期望把一本书或者一个项目完全吃透,只希望能用数量去 ...
- DOM_05之DOM、BOM常用对象
1.HTML DOM常用对象之Table:①创建:createTHead():createTBody():createTFoot():②删除:deleteTHead():deleteTFoot():③ ...
- 玩转Django的POST请求 CSRF
玩转Django的POST请求 CSRF 不少麻油们玩django都会碰到这个问题,POST请求莫名其妙的返回 403 foribidden,希望这篇博文能解答所有问题 三种方法 To enable ...
- .NET实现Office Excel自定义公式 广泛应用于报表与数据分析
在管理软件开发的功能点中,有相当一部分功能是与Excel做数据交互,产生Excel 数据报表.如果Excel报表的数据计算方法很有规律可循,则可以通过自定义公式来解决.比如常见的资产负债表,利润表,取 ...
- sublime text2小技巧
1. 文件快速导航: 这是sublime上面很好用的功能之一,ctrl+p可以调出窗口,菜单上的解释是gotoanythings ,确实如其所言,调出窗口后,直接输入关键字,可以在已打开的项目文件夹中 ...
- 前端工程师技能之photoshop巧用系列扩展篇——自动切图
× 目录 [1]初始设置 [2]自动切图 前面的话 随着photoshop版本的不断升级,软件本身增加了很多新的功能,也为切图工作增加了很多的便利.photoshop最新的版本新增了自动切图功能,本文 ...
- How Spring Boot Autoconfiguration Magic Works--转
原文地址:https://dzone.com/articles/how-springboot-autoconfiguration-magic-works In my previous post &qu ...
- Spring MVC 学习总结(七)——FreeMarker模板引擎与动态页面静态化
模板引擎可以让程序实现界面与数据分离,业务代码与逻辑代码的分离,这就提升了开发效率,良好的设计也使得代码复用变得更加容易.一般的模板引擎都包含一个模板解析器和一套标记语言,好的模板引擎有简洁的语法规则 ...