强连通图------(1)通过两次DFS或BFS判断是不是强连通图

17 篇文章 0 订阅

一、定义:

强连通图(Strongly Connected Graph)是指在有向图G中,如果对于每一对vi、vj,vi≠vj,从vi到vj和从vj到vi都存在路径,则称G是强连通图。

二、判断是不是强连通图的算法:

下面是Kosaraju基于DFS的简单算法,这算法对图进行了两次DFS遍历:

1) 将所有顶点初始化为未访问。

2)从任意顶点v开始进行图的DFS遍历。如果DFS遍历没有访问完所有顶点,则返回false

3)反转所有圆弧

4)将所有顶点标记为未在反向图中访问。

5)从相同的顶点v开始进行反向图的DFS遍历(与步骤2相同)。如果DFS遍历不访问所有顶点,则返回false。否则返回true

原理:

在这里插入图片描述
翻译下?
就是说:
对于无向图,如果从任意一个顶点v开始DFS或者BFS可以到达所有其他顶点,那么其他的顶点至少可以通过一条包含v的路径来到达除自己外的顶点。
对于有向图来说,如果从任意一个顶点v开始DFS或者BFS可以到达所有其他顶点,然后把有向图的边反向,在从顶点v开始DFS或者BFS可以再次到达所有其他顶点,
那么就意味着在原图中所有其他顶点都可以到达顶点v而如果v可以到达所有其他顶点,所有其他顶点又可以到达v,那么其他的顶点至少可以通过一条包含v的路径来到达除自己外的顶点。根据定义,这样图肯定就是强连通图了。

黄色字体解释:
“如果顶点u可以到达v,那么如果反转u和v之间的路径的边缘,则现在v可以等效地到达u,并且如果在原始点中没有从u到v的路径,则在转置v和u’之间没有路径"
在这里插入图片描述
来自:https://cs.stackexchange.com/questions/19652/kosaraju-s-algorithm-why-transpose

代码实现:

DFSBFS都写了,用的是BFS,要用DFS的话把isSC里的两个BFSUtil改成DFSUtil就可以

#include<iostream>
#include<list> 
#include<queue>
using namespace std;

class Graph
{
	int n;
	list<int>*adj; 	//邻接表 
	void DFSUtil(int u, bool visited[]); 
	void BFSUtil(int u, bool visited[]);
public:
	Graph(int _n){ n = _n;  adj = new list<int>[_n]; }
	~Graph(){  delete [] adj; }
	void addEdge(int v,int w);
	Graph getTranspose(); 
	bool isSC();		//返回是不是强连同图 
};
void Graph::addEdge(int v, int w)
{
	adj[v].push_back(w);
}
Graph Graph::getTranspose()		//有向图反向
{
	Graph g(n);
	for(int i = 0; i < n; i++)
	{
		list<int>::iterator it;
		for(it = adj[i].begin(); it != adj[i].end(); it++)
		{
			g.addEdge(*it, i);		//反向添加 
		} 
	}
	return g; 
}
void Graph::DFSUtil(int u,bool visited[])  //DFS
{
	visited[u] = true;
	list<int>::iterator it;
	for(it = adj[u].begin(); it != adj[u].end(); it++)
	{
		if(!visited[*it])
		{
			DFSUtil(*it,visited); 
		}
	}
} 
bool Graph::isSC()
{
	bool *visited = new bool[n];
	for(int i = 0; i < n; i++)
	{
		visited[i] = false;
	}
	BFSUtil(0,visited); 				//从0开始DFS 
	for(int i = 0; i < n; i++)
	{
		if(visited[i] == false) 		//不连通 
		{
			return false;
		}
	}
	Graph  gr = getTranspose(); 		//得到反向的有向图 
	for(int i = 0; i < n; i++)
	{
		visited[i] = false;
	}
	gr.BFSUtil(0,visited); 			  //从0开始对反向的有向进行DFS 
	for(int i = 0; i < n; i++)
	{
		if(visited[i] == false) 		//不连通 
		{
			return false;
		}
	}
	return true;	
}
void Graph::BFSUtil(int u,bool visited[]) 		//BFS
{
	queue<int> q;
	q.push(u);
	visited[u] = true;
	list<int>::iterator it;
	while(!q.empty())
	{
		int v = q.front();
		q.pop();
		for(it = adj[v].begin(); it != adj[v].end(); it++)
		{
			if(!visited[*it])
			{
				q.push(*it);
				visited[*it] = true;
			} 
		}
	}
}
int main() 
{ 
    Graph g1(5); 
    g1.addEdge(0, 1); 
    g1.addEdge(1, 2); 
    g1.addEdge(2, 3); 
    g1.addEdge(3, 0); 
    g1.addEdge(2, 4); 
    g1.addEdge(4, 2); 
    g1.isSC()? cout << "Yes\n" : cout << "No\n"; 
  
    Graph g2(4); 
    g2.addEdge(0, 1); 
    g2.addEdge(1, 2); 
    g2.addEdge(2, 3); 
    g2.isSC()? cout << "Yes\n" : cout << "No\n"; 
  
    return 0; 
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值