1. 程式人生 > >求解強連通分量的一種方法

求解強連通分量的一種方法

如果對於任意兩個不同的頂點u和v,存在一個從u到v的有向路徑以及從v到u的有向路徑,這樣的有向圖被稱為是強連通的。一般來說,一個有向圖的頂點可以分割成一些互不相交的最大子集,每個子集的頂點之間可以通過有向圖中的有向路徑相互訪問,這些子集被稱為強連通分量。
下面的方法來自《演算法設計與分析基礎》作者: Anany Levitin 譯者: 潘彥

下面三步說的頂點變成死端是遞迴的dfs出棧的順序。

第一步:對給定的有向圖執行一次DFS遍歷,然後按照頂點變成死端的順序對它們進行編號。
第二步:顛倒有向圖所有邊方向。
第三步:對於新的有向圖,從仍未訪問過的頂點中編號最大的頂點開始(而且如果有必要的話,可以重新開始)做一遍DFS遍歷。

鄰接表

package d;



public class AGraph {
int n,e;
VNode adjlist[];
public AGraph(int n) {
	super();
	this.n = n;
	adjlist=new VNode[n];
}

}

package d;

class ArcNode{

int adjvex;  ArcNode nextarc;

ArcNode reverse_nextarc;




public ArcNode() {

}

 

public ArcNode (int adjvex){

this.adjvex=
adjvex; }; } package d; class VNode{//鄰接矩陣的頂點也可以用這個 ArcNode firstarc; ArcNode reverse_firstarc; int Serial_number;//DFS訪問後按照死端編號 char info; public VNode(char info) { this.info = info; } public VNode() { super(); } }

主程式

package d;


import java.util.Comparator;

class Mycomparator implements
Comparator<VNode> { public int compare(VNode v1,VNode v2) { int a=v1.Serial_number; int b=v2.Serial_number; if (a>b) { return -1;//按照這種方式排序 } else if (a<b) { return 1; } return 0; } } public class Main { public static int top=-1; public static int[]stack; //正常的DFS public static void DFS1(AGraph a) { //-1表示未訪問,-2表示是起始節點(前面沒東西) stack=new int[a.n]; int visited[]=new int[a.n]; for(int i=0;i<a.n;i++)//如果要求路徑的話 visited[i]=-1;//visited設為-1 for(int i=0;i<a.n;i++) if(visited[i]==-1)//這裡也改為-1 dfs3(a,i,visited,-2);//-2表示是起始節點 } public static void dfs3(AGraph a,int start,int visited[],int before) { //visited必須初始化為-1,不然初始化為0 //分不清visited==0是沒有被訪問還是被訪問了前面一個是0 visited[start]=before; //進棧操作(按照課本上那種進棧順序) ArcNode arc=a.adjlist[start].firstarc; while(arc!=null) { if(visited[arc.adjvex]==-1) { dfs3(a,arc.adjvex,visited,start);} arc=arc.nextarc; } a.adjlist[start].Serial_number=++top; stack[top]=start; } //反向鄰接表的DFS: public static void reverse_DFS1(AGraph a) { //-1表示未訪問,-2表示是起始節點(前面沒東西) int visited[]=new int[a.n]; for(int i=0;i<a.n;i++)//如果要求路徑的話 visited[i]=-1;//visited設為-1 while(top!=-1) { int i=stack[top--]; if(visited[i]==-1)//這裡也改為-1 { System.out.print("當前強連通分量為:"); reverse_dfs3(a,i,visited,-2);//-2表示是起始節點 System.out.println(); } } } public static void reverse_dfs3(AGraph a,int start,int visited[],int before) { //visited必須初始化為-1,不然初始化為0 //分不清visited==0是沒有被訪問還是被訪問了前面一個是0 visited[start]=before; System.out.print(a.adjlist[start].info+" "); ArcNode arc=a.adjlist[start].reverse_firstarc; while(arc!=null) { if(visited[arc.adjvex]==-1) { reverse_dfs3(a,arc.adjvex,visited,start); } arc=arc.reverse_nextarc; } } public static void reverse(AGraph a) {//顛倒有向圖的方向,作反向鄰接表 ArcNode [] temp=new ArcNode[a.n];//第i個反向時 現在對應的ArcNode for(int i=0;i<a.n;i++) { ArcNode arc=a.adjlist[i].firstarc; while(arc!=null) { if(temp[arc.adjvex]==null) { a.adjlist[arc.adjvex].reverse_firstarc=new ArcNode(i); temp[arc.adjvex]=a.adjlist[arc.adjvex].reverse_firstarc; } else { temp[arc.adjvex].reverse_nextarc=new ArcNode(i); temp[arc.adjvex]=temp[arc.adjvex].reverse_nextarc; } arc=arc.nextarc; } } } public static void main(String[] args) { AGraph a=new AGraph(8); for(int i=0;i<a.n;i++) a.adjlist[i]=new VNode((char)('a'+i)); ArcNode arc; a.adjlist[0].firstarc=new ArcNode(1); a.adjlist[1].firstarc=new ArcNode(6); a.adjlist[2].firstarc=new ArcNode(3); a.adjlist[2].firstarc.nextarc=new ArcNode(4); a.adjlist[3].firstarc=new ArcNode(1); a.adjlist[3].firstarc.nextarc=new ArcNode(6); a.adjlist[4].firstarc=new ArcNode(7); a.adjlist[5].firstarc=new ArcNode(0); a.adjlist[5].firstarc.nextarc=new ArcNode(1); a.adjlist[6].firstarc=new ArcNode(5); a.adjlist[7].firstarc=new ArcNode(2); a.adjlist[7].firstarc.nextarc=new ArcNode(3); DFS1(a); System.out.println(); /*不能排序的,一排序就會改變陣列的順序 Comparator<VNode> cmp=new Mycomparator(); Arrays.sort(a.adjlist,cmp); for (int i=0;i<a.n;i++) { System.out.print(a.adjlist[i].info+" "); } */ //直接用stack出棧就行就行 reverse(a); /* ArcNode arcc; for(int i=0;i<a.n;i++) { System.out.print(i); arcc=a.adjlist[i].reverse_firstarc; while(arcc!=null) { System.out.print(arcc.adjvex); arcc=arcc.reverse_nextarc; } System.out.println(); }*/ reverse_DFS1(a); } }