【问题描述】
给定一个无向图,设计一个算法,判断该图中是否存在关节点,并划分双连通分量。
1 package org.xiu68.exp.exp9; 2 3 import java.util.Stack; 4 5 public class Exp9_3 { 6 7 //无向图的双连通分量问题 8 public static void main(String[] args) { 9 // TODO Auto-generated method stub 10 int[][] graph=new int[][]{ 11 {0,1,1,0,0}, 12 {1,0,1,0,0}, 13 {1,1,0,1,1}, 14 {0,0,1,0,1}, 15 {0,0,1,1,0} 16 }; 17 MGraph1 m=new MGraph1(graph); 18 m.bicompDFS(0); 19 //运行结果 20 /* 21 双连通部件: 22 (4,2) (3,4) (2,3) 23 双连通部件: 24 (2,0) (1,2) (0,1) 25 */ 26 } 27 28 } 29 30 31 //邻接矩阵表示无向图 32 class MGraph1{ 33 private int vexNum; //顶点数量 34 private int[][] edges; //边 35 36 private Stack<Edge> edgeStack; //边栈 37 private int[][] visitedEdge; //记录哪条边已经访问过,1为访问过,0为未访问过 38 39 private int[] color; //记录顶点的访问状态,-1为未访问到,0为正在搜索中,1为已搜索完成 40 private int clock; //访问时刻 41 private int[] pre; //记录顶点的访问时间 42 private int[] post; //记录顶点的结束访问时刻 43 44 45 public MGraph1(int[][] edges) { 46 this.edges = edges; 47 this.vexNum=edges.length; 48 this.color=new int[vexNum]; 49 this.pre=new int[vexNum]; 50 this.post=new int[vexNum]; 51 this.clock=1; 52 this.edgeStack=new Stack<>(); 53 this.visitedEdge=new int[vexNum][vexNum]; 54 55 //初始化所有结点为未访问状态 56 for(int i=0;i<vexNum;i++){ 57 color[i]=-1; 58 } 59 } 60 61 //返回从v出发,经过一条其后代组成的边包括回退边,所能访问到的顶点的最小的pre值 62 public int bicompDFS(int v){ 63 //color[v]的值:-1为未访问到,0为正在搜索中,1为已搜索完成 64 color[v]=0; //顶点v正在搜索中 65 pre[v]=clock; //顶点v的访问时刻 66 clock++; 67 68 int back=pre[v]; //表示从v出发,经过一条其后代组成的边包括回退边,所能访问到的顶点的最小的pre值 69 70 for(int i=0;i<vexNum;i++){ 71 if(edges[v][i]==1 && color[i]!=1 && visitedEdge[v][i]!=1){ //顶点v和i之间有边未访问过 72 73 edgeStack.push(new Edge(v,i)); //放入边栈中 74 visitedEdge[v][i]=visitedEdge[i][v]=1; //记录边已访问过 75 76 if(color[i]==-1){ //树边 77 int wBack=bicompDFS(i); 78 79 if(wBack>=pre[v]){ //说明v的子树没有回路关联到v的祖先 80 System.out.println("双连通部件: "); 81 Edge e=edgeStack.pop(); 82 while(true){ 83 System.out.print("("+e.getHead()+","+e.getTail()+") "); 84 if(e.getHead()==v && e.getTail()==i) 85 break; 86 e=edgeStack.pop(); 87 } 88 System.out.println(); 89 } 90 if(wBack<back) 91 back=wBack; //记录从v开始经过的顶点的最小的pre值 92 }else if(color[i]==0){ //回边 93 if(pre[i]<back) 94 back=pre[i]; //记录从v开始经过的顶点的最小的pre值 95 } 96 }//if 97 }//for 98 99 post[v]=clock; 100 clock++; 101 color[v]=1; 102 103 return back; 104 } 105 } 106 107 class Edge{ 108 private int head; //边的头 109 private int tail; //边的尾 110 111 public Edge(int head,int tail){ 112 this.head=head; 113 this.tail=tail; 114 } 115 116 public int getHead() { 117 return head; 118 } 119 120 public void setHead(int head) { 121 this.head = head; 122 } 123 124 public int getTail() { 125 return tail; 126 } 127 128 public void setTail(int tail) { 129 this.tail = tail; 130 } 131 132 }