快乐地打牢基础(2)——强连通分量

一、定义


在有向图 G {G} G中,如果两个顶点 u , v {u,v} u,v间尊在一条 u {u} u v {v} v的路径且也存在一条 v {v} v u {u} u的路径,则称这两个顶点 u , v {u,v} uv是强联通的(strongly
connected)。如果有向图 G {G} G是一个强连通图,有向非强连通图的极大强连通子图,称为强连通分量(strongly connected components)。

极大强连通子图: G {G} G是一个极大强连通子图,当且仅当 G {G} G是一个强连通子图且不存在另一个强连通子图 G ′ {G'} G,使得 G {G} G G ′ {G'} G的真子集。

举个例子:
在下图中,子图 { 1 , 2 , 3 , 4 } {\{1,2,3,4\}} { 1,2,3,4}是一个强连通分量,因为顶点 1 , 2 , 3 , 4 {1,2,3,4} 1,2,3,4两两可达, { 5 } , { 6 } {\{5\},\{6\}} { 5},{ 6}也是两强连通分量。
在这里插入图片描述
应用:若将原图所有的强连通分量都缩为一个点,那么原图就会形成一个DAG(有向无环图)

在这里插入图片描述

二、Kosaraju算法


基于两次DFS的有向图强连通子图的算法。时间复杂度 O ( n + m ) {O(n+m)} O(n+m)

算法过程:
Ⅰ.对原有向图 G {G} G进行DFS,记录结点访问完的顺序 d [ i ] {d[i]} d[i], d [ i ] {d[i]} d[i]表示第 i {i} i个访问完的结点是 d [ i ] {d[i]} d[i]

Ⅱ.选择具有最晚访问完的顶点,对反向图 G T {GT} GT进行DFS,删除能够遍历到的顶点,这些顶点构成一个强连通分量。

Ⅲ.如果还有顶点没有删除,继续第二步,否则算法结束。

举个栗子:
在这里插入图片描述
第一次遍历的访问次序是1,2,3,4;访问完成的顺序是3,2,1,4.。

第二次遍历是按照“访问完成的顺序”从后向前访问,所以第二次是先从4开始,然后是1,2,最后是3。

最后我们可以求出三个强连通分量: { ( 4 ) , ( 1 , 2 ) , ( 3 ) } {\{(4),(1,2),(3)\}} { (4),(1,2),(3)}

算法模板:

#include<bits/stdc++.h>
using namespace std;

const int Max = 101;
int vis[Max]={
   0},mapp[Max][Max],d[Max],n,t=0;
void dfsone(int x) {
   
	vis[x] = 1;
	for(int i = 1; i <= n; i++) {
   
		if(!vis[i] && mapp[x][i]) dfsone(i);
	}
	d[++t] = x;
}
void dfstwo(int x) {
   
	vis[x] = t;
	for(int i = 1; i <= n; i++)
		if(!vis[i] && mapp[i][x]) dfstwo(i);
}

void Kosaraju() {
   
	int i;
	t = 0;
	//进行第一次DFS遍历
	for(i = 1; i<= n; i++)
		if(!vis[i]) dfsone(i);
	memset(vis,0,sizeof(vis));
	t = 0;
	printf("\nd[i]:\n"
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值