求解強連通分量的一種方法
阿新 • • 發佈:2018-12-09
如果對於任意兩個不同的頂點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);
}
}