一、定义:
强连通图(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
代码实现:
DFS
和BFS
都写了,用的是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;
}