【问题描述】
给定一个有向图,设计一个算法,求解并输出该图的各个强连通分量。
package org.xiu68.exp.exp9; import java.util.ArrayList;
import java.util.List;
import java.util.Stack; public class Exp9_2 {
public static void main(String[] args) {
int[][] graph=new int[][]{
{0,1,1,0,0},
{1,0,0,0,0},
{0,0,0,1,0},
{0,0,0,0,1},
{0,0,1,0,0}
};
MGraph m1=new MGraph(graph, 5);
m1.getSccs();
}
} class MGraph{
private int[][] graph; //有向图
private int[][] rGraph; //有向图的反向图
private int vexNum; //顶点数量
Stack<Integer> stack; //存储反向图深度优先遍历的post值,从大到小排序 public MGraph(int[][] graph,int vertexNum){
this.graph=graph;
this.vexNum=vertexNum;
stack=new Stack<>();
rGraph=new int[vexNum][vexNum]; //反向图 //求原图的反向图
for(int i=0;i<vexNum;i++){
for(int j=i+1;j<vexNum;j++){
rGraph[i][j]=graph[j][i];
rGraph[j][i]=graph[i][j];
}
}
} public void getSccs(){
rDFSTraverse(); //先对反向图进行深度优先遍历 boolean[] visited=new boolean[vexNum]; //记录深度优先遍历原图过程中已经访问的顶点 List<List<Integer>> sccs=new ArrayList<>(); //存放每一个强连通部件对应的顶点
int n=0; //第几个强连通部件
while(!stack.isEmpty()){
int v=stack.pop();
if(!visited[v]){
sccs.add(new ArrayList<Integer>());
DFS(visited,v,sccs,n);
n++;
}
}
//打印强连通部件
for(int i=0;i<sccs.size();i++){
System.out.print("第"+i+"个强连通部件:");
for(int j=0;j<sccs.get(i).size();j++){
System.out.print(sccs.get(i).get(j)+" ");
}
System.out.println();
}
}
/*
* 对原图进行深度优先遍历
* 在汇点强连通部件中对某个顶点进行深度优先遍历则刚好访问该强连通部件的所有顶点
*/
private void DFS(boolean[] visited,int v,List<List<Integer>> sccs,int n){
sccs.get(n).add(v);
visited[v]=true;
for(int i=0;i<vexNum;i++){
if(graph[v][i]==1 && !visited[i])
DFS(visited,i,sccs,n);
}
} //**************************************************************
/*
* 对反向图进行深度优先遍历,post值最大的顶点将位于反向图中的一个源点强连通部件,
* 也就是原图中的某个汇点连通部件的某个顶点
* 求得各个顶点的post值,压入栈中
*/
public void rDFSTraverse(){
boolean[] visited=new boolean[vexNum];
for(int i=0;i<vexNum;i++){
if(!visited[i]){
rDFS(visited,stack,i);
}
}
}
//对反向图做深度优先遍历
private void rDFS(boolean[] visited,Stack<Integer> stack,int v){
visited[v]=true;
for(int i=0;i<vexNum;i++){
if(rGraph[v][i]==1 && !visited[i]){
rDFS(visited,stack,i);
}
}
stack.push(v);
}
}