Kosaraju算法

该算法旨在得到深度优先后续排列后的递归探索中,每次调用DFS的所有顶点都属于同一强联通分量。所以可以这么理解:当递归进入一个强联通分量时,把他锁死在这个强联通分量中(即不能从该强联通分量中的任意顶点达到外部顶点)

下面来说说该算法的思路,我认为这是一个十分巧妙的算法,有兴趣的同学可以去看算法导论这本书,我觉得关于这个算法的解释讲的特别好。

该算法的核心思想就是两次DFS遍历,可以先遍历原图再遍历转置图(即所有边都反向的图),也可以先遍历转置图再遍历原图。

下面我们按先遍历原图再遍历转置图来说一说该算法的大致实现流程:

  1. 深度优先遍历原图G(V,E),并记录每个结点遍历结束的时间(将该点的所有子孙结点都遍历完从该点退出的时间即为该点遍历的结束时间,由此可知该结点的结束时间比他的所有子孙节点的结束时间都要晚)
  2. 将该图逆转得到转置图(需要明白的是转置图的强连通分量和原图的强连通分量完全相同,即逆转图不会改变图的强连通分量)
  3. 在转置图上每次取出结束时间最晚且未遍历过的点进行深度优先遍历,并将遍历过的结点标记(下次遍历不再遍历这些被标记过的点),每一次深度优先遍历得到的点即为一个强连通分量。

那么为什么按上述方法的到的为强连通分量呢?且听我慢慢道来:

要理解kosaraju算法,首先得理解拓扑排序,即访问每个强连通分量都得有一个先后顺序,使得每次访问一个强连通分量时,都不能从该强连通分量到达其他强连通分量(即该强连通分量中若有边指向其他强连通分量,则他所指向的强连通分量一定已经被访问过了)

那么如何使得每次访问一个强连通分量时,都不能从该强连通分量中的任意顶点达到外部顶点呢?按上述所说的每次取出遍历结束时间最大的点,在转置图中进行深度优先遍历即可完美解决该问题。

我们实际上是在以拓扑排序的次序来访问分量图中的结点。(分量图:即将每个强连通分量都浓缩成一个结点得到的一个有向无环图,该图中的每一个结点对应原图G的一个强连通分量)

(结点的发现时间:即第一次访问到该结点的时间;结点的完成时间:即DFS从该结点退出时的时间,同遍历结束时间的意思相同)

这里的d(C)<d(C')指的是在第一次DFS中强连通分量C中的结点要比C'中的结点先访问(不一定C中的所有结点都比C'要先访问,但是C中一定至少存在一个结点的访问时间要比C'中的所有结点都要早);同理d(C)>d(C')表示C’中的结点要比C中的结点先访问。

根据上述定理可知,将原图逆转后的到的分量图中的边都是由 f 较小的强连通分量指向 f 较大的强连通分量。

这里的E^T是指的转置图的边。

所以当我们每次取出完成时间最晚的那个顶点进行深度优先遍历时,从该顶点所表示的强连通分量的所有出边(即指出该强连通分量的边)所指向的强连通分量一定已经访问(因为他们的 f 要大于该强连通分量的 f ,这即是拓扑排序的一个应用),所以不可能有一条边可以跳出该强连通分量,故DFS被锁死在该强连通分量中,所以该次DFS所访问的点即为该强连通分量中的所有点。

下面是代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX_SIZE 100
typedef int Elemtype;
typedef struct{int vexsnum;int arcsnum;Elemtype vexs[MAX_SIZE];//结点表 int arcs[MAX_SIZE][MAX_SIZE];//临接矩阵
}Mgraph;//图结构 void DFS(Mgraph G,int i,int key);//从结点i开始进行深搜
int DFStraving(Mgraph G,int key);//当key为1时,在深搜的同时打印结点
void creat_graph(Mgraph* G);//创建有向图
int get_location(Mgraph G,Elemtype v);//找到元素v在结点表中的位置
void recreat(Mgraph* G);//逆转原图 bool visited[MAX_SIZE]={false};
int finish[MAX_SIZE]={0};//记录结点访问完成的时间
int time=0;int main()
{Mgraph G;creat_graph(&G);int cnt;DFStraving(G,0);recreat(&G);cnt=DFStraving(G,1);printf("强连通分量的个数:%d\n",cnt);return 0;
} void DFS(Mgraph G,int i,int key)
{visited[i]=true;int j;if(key==1)printf("%d ",G.vexs[i]);for(j=0;j<G.vexsnum;j++)if(G.arcs[i][j]&&!visited[j])DFS(G,j,key);if(key==0)finish[i]=++time;
}int DFStraving(Mgraph G,int key)//第一次调用时key为0,为的是得到finish数组,第二次调用时key为1
{int i,cnt=0;if(key==0){for(i=0;i<G.vexsnum;i++)if(!visited[i])DFS(G,i,key);}else if(key==1){printf("强连通分量:\n");memset(visited,0,MAX_SIZE*sizeof(bool)); while(1){int max=-1;for(i=0;i<G.vexsnum;i++)//找出完成时间最大的点 {if(visited[i]==false&&max==-1)max=i;if(visited[i]==false&&max!=-1&&finish[max]<finish[i])max=i;}if(max==-1)//所有点都已经被访问 break;DFS(G,max,key);cnt++;printf("\n");}}return cnt;
}void creat_graph(Mgraph* G)
{printf("请输入有向图的结点数和边数:");scanf("%d%d",&(G->vexsnum),&(G->arcsnum));int i;memset(G->arcs,0,(MAX_SIZE)*(G->vexsnum)*sizeof(int));//初始化邻接矩阵printf("请输入各结点的值:");for(i=0;i<G->vexsnum;i++)scanf("%d",&(G->vexs[i])); printf("请输入有向边所依附的两结点的值(从结点1指向结点2):");Elemtype m,n;int x,y;for(i=0;i<G->arcsnum;i++){scanf("%d%d",&m,&n);x=get_location(*G,m);y=get_location(*G,n);G->arcs[x][y]=1;}printf("有向图创建完成!\n");
}int get_location(Mgraph G,Elemtype v)
{int i;for(i=0;i<G.vexsnum&&G.vexs[i]!=v;i++);return i;
}void recreat(Mgraph* G)
{int i,j,e;for(i=0;i<G->vexsnum;i++)for(j=i;j<G->vexsnum;j++)//这里很细节,不能从j=0开始,否则会有重复,做使边做两次交换,相当于没有对图做逆转 {if(G->arcs[i][j]!=G->arcs[j][i]){e=G->arcs[i][j];G->arcs[i][j]=G->arcs[j][i];G->arcs[j][i]=e;}}
}

Kosaraju算法求强连通分量相关推荐

  1. bzoj1051[kosaraju算法]求强连通分量

    之前一直用的是tarjan第一次学习到这个来试一下. 唔,就是裸的算法,然后如果出度为0的点只有一个,输出这个点的大小. #include<iostream> #include<cs ...

  2. 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...

  3. 迷宫城堡 HDU - 1269 (塔尖算法求强连通分量)

    为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以 ...

  4. POJ2186——并查集+Tarjan算法求强连通分量

    算法讨论:这题陷阱比较多.首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中.这个我们用并查集来实现就可以了.强连通分量的求法就很简单了,正 ...

  5. Tarjan 算法思想求强连通分量及求割点模板(超详细图解)

    割点定义 在一个无向图中,如果有一个顶点,删除这个顶点及其相关联的边后,图的连通分量增多,就称该点是割点,该点构成的集合就是割点集合.简单来说就是去掉该点后其所在的连通图不再连通,则该点称为割点. 若 ...

  6. tarjan算法求解强连通分量问题

    Part1:有向图的强连通分量: 一个连通图只有一个联通分量就是自身,非连通图有多个连通分量. 在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从v ...

  7. 算法竞赛——强连通分量

    强连通分量 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图也可以说,在强连 ...

  8. Tarjan算法(求强连通分量与割点)

    Tarjan算法,是以一位计算机界大佬的名字命名的算法,多用于解决LCA,割点,强连通分量等问题,下面是其发明者的简短介绍. Robert Tarjan,计算机科学家,以LCA.强连通分量等算法闻名. ...

  9. Targan 算法[有向图强连通分量]

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

最新文章

  1. mxnet加载预训练
  2. Jquery之编辑不可修改
  3. php中include和require,在PHP中include和require到底有什么区别呢?
  4. getParentalNodePaths、osg::NodePathList、osg::NodePath详解
  5. 微课系列(6):Python关键字else的三种用法
  6. 图像处理基础(三)_像素之间的3种关系
  7. C语言实现多人坦克大战
  8. 简单个人网页设计 静态HTML动物主题网页 DW个人网站模板 简单宠物网页作品代码 个人网页制作 个人网页Dreamweaver设计与实现
  9. 微信小程序 首页弹出广告的demo
  10. 怎样清理计算机c盘东西,怎样清理电脑c盘无用的东西(电脑c盘垃圾清理技巧)...
  11. 一文带你搞懂Vue中的Excel导入导出
  12. PS下的遥感图像修图
  13. 如何消除win10文件右上角的蓝色箭头
  14. java:去除数组重复元素的四种方法
  15. 系列解读Dropout
  16. ionic capacitor 开发APP问题集合
  17. 基于遗传算法优化的Elman神经网络数据预测-附代码
  18. 中国企业出海第五波浪潮,泛娱乐互联网向全球扩张
  19. 计算机科学与技术高校学科评估排名,教育部06高校学科评估排名:0812 计算机科学与技术...
  20. 万象OL免刷 云百度免刷

热门文章

  1. mc服务器怎么修改祭坛的概率,邪术祭坛 (Eldritch Altar)
  2. 量子计算 11 NSA的随机数阴谋
  3. 俄罗斯方块linux服务器,基与Linux环境下 C 俄罗斯方块
  4. python爬取旅游信息_Python 爬取 13 个旅游城市,告诉你五一大家最爱去哪玩?
  5. roscore失败,提示RLException: Unable to contact my own server
  6. 如何把flv转换成mp3格式 音频转换器哪个好
  7. 微信公众号开发----测试号的使用
  8. myeclipse下使用maven搭建SSM(spring、springmvc、mybatis)框架
  9. js的初识及数据类型简介
  10. Android Study 之通过DialogFragment玩转高仿IOS弹框~ ^.^