强连通性:顶点v和w是互相可达的
有向图强连通:任意两个顶点都是强连通的
强连通分量:有向图中相互连通的顶点组成的最大子集
强连通分量--Kosaraju算法
给定一张有向图G,计算其反向图GR
将反向图进行顶点排序,取得逆后序顺序
按照GR逆后序顺序进行dfs搜索,在构造函数中同一个dfs递归调用中访问到的顶点属于同一个强连通分量
给定有向图G
求出反向图GR
//有向图反转
public Digraph reverse(){
Digraph R = new Digraph(V);
for(int v=0; v<V; v++){
for(int w : adj[v]){
R.addEdge(w, v);
}
}
return R;
}
对于反向图进行顶点排序 https://blog.csdn.net/u014106644/article/details/90444801
//对g的反向图进行顶点排序
DepthFirstOrder order = new DepthFirstOrder(g.reverse());
按照GR逆后序顺序进行dfs搜索,在构造函数中同一递归调用访问的顶点属于同一强连通分量
public class KosarajuSCC {
private boolean[] marked;
private int[] id;
private int count;
public KosarajuSCC(Digraph g){
marked = new boolean[g.V()];
id = new int[g.V()];
//对g的反向图进行顶点排序
DepthFirstOrder order = new DepthFirstOrder(g.reverse());
//对逆后序进行dfs 在同一个dfs递归调用中出现的顶点属于同一强连通分量
for(int s : order.reversePost()){
if(!marked[s]){
dfs(g, s);
count++;
}
}
}
private void dfs(Digraph g, int s) {
marked[s] = true;
id[s] = count;
System.out.println("s " + s + " " + count);
for(int v : g.adj(s)){
if(!marked[v]){
dfs(g, v);
}
}
}
public boolean stronglyConnected(int v, int w){
return id[v] == id[w];
}
public int id(int v){
return id[v];
}
public int count(){
return this.count;
}
public static void main(String[] args) {
Digraph g = GraphUtils.getDiGraphPointG3().getG();
System.out.println(g.toString());
KosarajuSCC scc = new KosarajuSCC(g);
System.out.println(Arrays.toString(scc.id));
}
}
最终结果:
[1, 0, 1, 1, 1, 1, 3, 4, 4, 2, 2, 2, 2]
Kosaraju算法证明
dfs路径搜索的特点:
如果存在路径s-->v,则首先dfs(s)开始----dfs(v)开始----dfs(v)结束----dfs(s)结束
1.每个和s强连通的顶点v都会在构造函数调用的dfs(G,s)被访问到
s,v强连通说明s-->v v-->s 用反证法证明:
假定v没有再dfs(G,s)中访问到,由于s-->v,则必定v在之前已经被访问过;
又因为v-->s,如果v之前访问过则s也必定访问过,因此dfs(G,s)不会调用,即假设错误;
即每个和s强连通的顶点v都会在构造函数调用的dfs(G,s)被访问到
2.构造函数dfs(G,s)中所到达的任意顶点v必定与s是强连通的
由于dfs(G,s)访问到v则必定存在s-->v 只需要证明在G中有v-->s即可;
要证明G中有v-->s,只需要证明在GR中有s-->v
在GR中进行dfs,如果dfs(G,v)在dfs(G,s)之前结束,则说明在GR中存在路径s-->v,有两种情况:
dfs(G,v)在dfs(G,s)调用之前调用,在dfs(G,s)调用之前结束 不可能,因为在G中有s-->v,则GR中有v-->s,即如果dfs(G,v)开始调用,则必定会在递归中调用dfs(G,s),因此不可能在dfs(G,s)调用之前结束;
dfs(G,v)在dfs(G,s)调用之后调用,在dfs(G,s)结束之前结束,该情况说明含有路径s-->v