Ex3_15 判断图是否是一个强连通分量 判断点是否在汇点强连通分量中_十一次作业

(a) 可以用图中的每一个顶点表示街道中的每个十字路口,由于街道都是单行的,所以图是有向图,若从一个十字路口都有一条合法的路线到另一个十字路口,则图是一个强连通图。即要验证的是图是否是一个强连通图。

 (b) 若从市政厅沿着合法路线到达任何一个地方都有合法路线返回则说明市政厅位于一个有向图中的一个汇点强连通部件中。

  1 package org.xiu68.ch03.ex11;
  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 import java.util.Stack;
  6 
  7 public class Ex3_15 {
  8 
  9     public static void main(String[] args) {
 10         // TODO Auto-generated method stub
 11         int[][] edges=new int[][]{
 12             {0,1,0,0},
 13             {0,0,1,0},
 14             {0,0,0,1},
 15             {1,0,0,0}
 16         };
 17         MGraph1 m1=new MGraph1(edges);
 18         m1.checkSC(0);  //强连通图
 19         
 20         System.out.println("***************************");
 21         int[][] edges1=new int[][]{
 22             {0,1,0,1},
 23             {0,0,1,0},
 24             {0,0,0,1},
 25             {0,0,0,0}
 26         };
 27         MGraph1 m2=new MGraph1(edges1);
 28         m2.checkSC(0);
 29         for(int i=0;i<4;i++){
 30             System.out.print(i+":");
 31             m2.isInSinkSCC(i);
 32         }
 33         //输出
 34         /*
 35          非强连通图
 36         0:不存在汇点强连通分量中
 37         1:不存在汇点强连通分量中
 38         2:不存在汇点强连通分量中
 39         3:存在汇点强连通分量中
 40         */
 41         
 42         System.out.println("***************************");
 43         int[][] edges3=new int[][]{
 44             {0,0,0,0,0,0,0},
 45             {1,0,0,1,0,0,0},
 46             {1,0,0,1,0,0,0},
 47             {0,0,0,0,1,1,0},
 48             {0,0,0,1,0,0,1},
 49             {0,0,0,1,0,0,1},
 50             {0,0,0,0,1,1,0}
 51         };
 52         MGraph1 m3=new MGraph1(edges3);
 53         for(int i=0;i<edges3.length;i++){
 54             System.out.print(i+":");
 55             m3.isInSinkSCC(i);
 56         }
 57         //输出
 58         /*
 59         0:存在汇点强连通分量中
 60         1:不存在汇点强连通分量中
 61         2:不存在汇点强连通分量中
 62         3:存在汇点强连通分量中
 63         4:存在汇点强连通分量中
 64         5:存在汇点强连通分量中
 65         6:存在汇点强连通分量中
 66         */
 67     }
 68 
 69 }
 70 
 71 
 72 class MGraph1{
 73     private int[][] edges;                //有向图
 74     private int[][] rEdges;                //有向图的反向图
 75     private int vexNum;                    //顶点数量
 76     private Stack<Integer> stack;        //存储反向图深度优先遍历的post值
 77     
 78     public MGraph1(int[][] edges){
 79         this.edges=edges;
 80         this.vexNum=edges.length;
 81         stack=new Stack<>();
 82         rEdges=new int[vexNum][vexNum];    //反向图
 83         
 84         //求原图的反向图
 85         for(int i=0;i<vexNum;i++){
 86             for(int j=i+1;j<vexNum;j++){
 87                 rEdges[i][j]=edges[j][i];
 88                 rEdges[j][i]=edges[i][j];
 89             }
 90         }
 91         
 92     }
 93     //******************************************************
 94     //验证图是否是强连通的
 95     /*
 96      * 先从某个顶点开始对原图进行深度优先遍历
 97      * 再从这个顶点开始对反向图做深度优先遍历
 98      * 若两次遍历都能访问所有顶点说明是强连通图
 99      */
100     public void checkSC(int v){
101         boolean[] visited=new boolean[vexNum];    //原图中已访问的顶点
102         dfs(edges,visited,v);
103         
104         boolean[] rVisited=new boolean[vexNum];    //反向图中已访问的顶点
105         dfs(rEdges,rVisited,v);
106         
107         for(int i=0;i<vexNum;i++){
108             if(!visited[i] || !rVisited[i]){
109                 System.out.println("非强连通图");
110                 return;
111             }
112         }
113         System.out.println("强连通图");
114     }
115     
116     //深度优先遍历
117     public void dfs(int[][] edges,boolean[] visited,int v){
118         visited[v]=true;
119         for(int i=0;i<vexNum;i++){
120             if(edges[v][i]==1 && !visited[i]){
121                 dfs(edges,visited,i);
122             }
123         }
124     }
125 //**************************************************************    
126     //判断一个顶点是否位于一个汇点强连通部件中
127     public void isInSinkSCC(int target){
128         rDFSTraverse();                                    //先对反向图进行深度优先遍历
129         
130         //List<List<Integer>> sccs=new ArrayList<>();    //存放每一个强连通部件对应的顶点
131         
132         boolean[] visited=new boolean[vexNum];            //记录深度优先遍历原图过程中非当前强连通分量已经访问的顶点
133         int[] visitedN=new int[vexNum];                    //记录顶点属于第几个强连通分量
134         boolean[] isSinkSCC=new boolean[vexNum];        //记录第i个强连通分量是否是汇点强连通部件,最多有vexNum个强连通部件        
135         int n=0;                                        //第几个强连通部件    
136         
137         for(int i=0;i<vexNum;i++){
138             visitedN[i]=-1;
139             isSinkSCC[i]=true;
140         }
141                                             
142         while(!stack.isEmpty()){
143             int v=stack.pop();
144             if(!visited[v]){
145                 //sccs.add(new ArrayList<Integer>());
146                 List<Integer> vexs=new ArrayList<>();    //记录第n个强连通分量的顶点
147                 
148                 DFS(visited,visitedN,v,vexs,isSinkSCC,n);
149                 for(int i=0;i<vexs.size();i++){
150                     //sccs.get(i).add(vexs.get(i));
151                     visited[vexs.get(i)]=true;
152                 }
153                 n++;
154             }
155         }
156         if(isSinkSCC[visitedN[target]]){
157             System.out.println("存在汇点强连通分量中");
158         }else{
159             System.out.println("不存在汇点强连通分量中");
160         }
161     }
162     /*
163      * 对原图进行深度优先遍历
164      * 在汇点强连通部件中对某个顶点进行深度优先遍历则刚好访问该强连通部件的所有顶点
165      */
166     private void DFS(boolean[] visited,int[] visitedN,int v,/*List<List<Integer>> sccs,*/
167             List<Integer> vexs,boolean[] isSinkSCC,int n){ 
168         //sccs.get(n).add(v);
169         vexs.add(v);
170         visitedN[v]=n;
171         for(int i=0;i<vexNum;i++){
172             if(edges[v][i]==1){            
173                 //若在一个汇点强连通部件中进行深度优先遍历,刚好得到该汇点强连通部件
174                 //若遍历到其他强连通分量的顶点说明该强连通分量不是汇点强连通分量
175                 if(visited[i]){        
176                     isSinkSCC[n]=false;
177                 }else if(visitedN[i]!=n){                
178                     DFS(visited,visitedN,i,/*sccs,*/vexs,isSinkSCC,n);
179                 }
180             }
181         }//for
182     }
183     
184     //**************************************************************    
185         /*
186          * 对反向图进行深度优先遍历,post值最大的顶点将位于反向图中的一个源点强连通部件,
187          * 也就是原图中的某个汇点连通部件的某个顶点
188          * 按post值从小到大,压入栈中
189          */
190         public void rDFSTraverse(){
191             boolean[] visited=new boolean[vexNum];
192             for(int i=0;i<vexNum;i++){
193                 if(!visited[i]){
194                     rDFS(visited,stack,i);
195                 }
196             }
197         }        
198         //对反向图做深度优先遍历
199         private void rDFS(boolean[] visited,Stack<Integer> stack,int v){
200             visited[v]=true;
201             for(int i=0;i<vexNum;i++){
202                 if(rEdges[v][i]==1 && !visited[i]){
203                     rDFS(visited,stack,i);
204                 }
205             }
206             stack.push(v);
207         }
208 }
View Code
原文地址:https://www.cnblogs.com/xiu68/p/7988793.html