Ex 3_25 图中每个顶点有一个相关价格..._十一次作业

(a)首先对有向无环图进行拓扑排序,再按拓扑排序的逆序依次计算每个顶点的cost值,每个顶点的cost值为自身的price值与相邻顶点间的cost值得最小值

(b)求出图中的每一个强连通分量,并把所有得强连通分量看成是一个有向无环图,设每一个强连通分量的price值为该强连通分量中顶点的最小的price值。然后再按(a)中的步骤处理DAG

  1 package org.xiu68.ch03.ex11;
  2 
  3 import java.util.ArrayDeque;
  4 import java.util.ArrayList;
  5 import java.util.List;
  6 import java.util.Stack;
  7 
  8 public class Ex3_25 {
  9     public static void main(String[] args) {
 10         // TODO Auto-generated method stub
 11         int[][] edges=new int[][]{
 12             {0,0,1,0,0,0},
 13             {0,0,0,1,0,0},
 14             {0,0,0,0,1,1},
 15             {0,0,0,0,1,1},
 16             {0,0,0,0,0,0},
 17             {0,0,0,0,0,0}
 18         };
 19         int[] price=new int[]{2,3,6,1,4,5};
 20         MGraph2 m1=new MGraph2(edges, price);
 21         m1.getCost();
 22         System.out.println("*****************");
 23         m1.getSccCost();
 24         //输出
 25         /*
 26         cost[0]:2
 27         cost[1]:1
 28         cost[2]:4
 29         cost[3]:1
 30         cost[4]:4
 31         cost[5]:5
 32         *****************
 33         cost[0]=2
 34         cost[1]=1
 35         cost[2]=4
 36         cost[3]=1
 37         cost[4]=4
 38         cost[5]=5
 39         */
 40         System.out.println("*******************");
 41         int[][] edges1=new int[][]{
 42             {0,0,0,0,0,0,0},
 43             {1,0,0,1,0,0,0},
 44             {1,0,0,1,0,0,0},
 45             {0,0,0,0,1,1,0},
 46             {0,0,0,1,0,0,1},
 47             {0,0,0,1,0,0,1},
 48             {0,0,0,0,1,1,0}
 49         };
 50         int[] price1=new int[]{6,7,9,5,3,4,2};
 51         MGraph2 m2=new MGraph2(edges1, price1);
 52         m2.getSccCost();
 53         //输出
 54         /*
 55         cost[0]=6
 56         cost[1]=2
 57         cost[2]=2
 58         cost[3]=2
 59         cost[4]=2
 60         cost[5]=2
 61         cost[6]=2
 62         */
 63     }
 64     
 65 }
 66 
 67 class MGraph2{
 68     private int[][] edges;                //有向图
 69     private int[][] rEdges;                //有向图的反向图
 70     private int vexNum;                    //顶点数量
 71     private int[] price;                //每个顶点的相对价格
 72     private int[][] sccEdges;            //强连通分量(DAG)之间的关系
 73     private Stack<Integer> stack;        //存储反向图深度优先遍历的post值
 74     
 75     public MGraph2(int[][] edges,int[] price){
 76         this.edges=edges;
 77         this.vexNum=edges.length;
 78         this.price=price;
 79         this.stack=new Stack<>();
 80         this.rEdges=new int[vexNum][vexNum];
 81         this.sccEdges=new int[vexNum][vexNum];
 82         
 83         //求原图的反向图
 84         for(int i=0;i<vexNum;i++){
 85             for(int j=i+1;j<vexNum;j++){
 86                 rEdges[i][j]=edges[j][i];
 87                 rEdges[j][i]=edges[i][j];
 88             }
 89         }
 90     }
 91     
 92     //**********************************************************
 93     //针对有向无环图,获取每个顶点的cost值
 94     public void getCost(){
 95         ArrayDeque<Integer> queue=new ArrayDeque<Integer>();    //存取拓扑排序的逆序
 96         int[] cost=new int[vexNum];
 97         for(int i=0;i<vexNum;i++)
 98             cost[i]=price[i];
 99         topoSort(queue,edges,vexNum);
100         
101         //依次处理每个顶点,每个顶点取自身的price值和邻接点的cost值得最小值
102         while(!queue.isEmpty()){
103             int v=queue.poll();
104             for(int i=0;i<vexNum;i++){
105                 if(edges[v][i]==1 && cost[i]<cost[v])
106                     cost[v]=cost[i];
107             }
108         }
109         for(int i=0;i<vexNum;i++)
110             System.out.println("cost["+i+"]:"+cost[i]);
111     }
112     //求拓扑排序的逆序
113     public void topoSort(ArrayDeque<Integer> queue,int[][] edgeArray,int vertexNum){    
114         boolean[] visited=new boolean[vertexNum];
115         for(int i=0;i<vertexNum;i++){
116             if(!visited[i])
117                 topoDFS(queue,visited,edgeArray,vertexNum,i);
118         }
119     }
120     //深度优先遍历求拓扑排序
121     public void topoDFS(ArrayDeque<Integer> queue,boolean[] visited,int[][] edgeArray,int vertexNum,int v){
122         visited[v]=true;
123         for(int i=0;i<vertexNum;i++){
124             if(edgeArray[v][i]==1 && !visited[i]){
125                 topoDFS(queue,visited,edgeArray,vertexNum,i);
126             }
127         }
128         queue.add(v);
129     }
130     
131     
132     
133     //****************************************************************
134     //针对所有有向图的情况,获取每个顶点的cost值
135     public void getSccCost(){
136         rDFSTraverse();                                    //先对反向图进行深度优先遍历
137         
138         List<List<Integer>> sccs=new ArrayList<>();        //存放每一个强连通部件对应的顶点
139         
140         boolean[] visited=new boolean[vexNum];            //记录深度优先遍历原图过程中非当前强连通分量已经访问的顶点
141         int[] visitedN=new int[vexNum];                    //记录顶点属于第几个强连通分量    
142         int n=0;                                        //第几个强连通部件    
143         
144         for(int i=0;i<vexNum;i++){
145             visitedN[i]=-1;
146         }
147         
148         //依次出栈,并从该顶点开始对原图进行深度优先遍历,获取每个强连通分量对应的顶点
149         //并获取DAG之间的关系
150         while(!stack.isEmpty()){
151             int v=stack.pop();
152             if(!visited[v]){
153                 sccs.add(new ArrayList<Integer>());
154                 List<Integer> vexs=new ArrayList<>();    //获取第n个强连通分量的顶点
155                 
156                 sccDFS(visited,visitedN,v,sccs,vexs,/*isSinkSCC,*/n);
157                 //为了知道遍历第n个强连通分量之前已经访问过哪些顶点
158                 //遍历完一个强连通分量再设visited值
159                 for(int i=0;i<vexs.size();i++){
160                     visited[vexs.get(i)]=true;
161                 }
162                 n++;
163             }
164         }
165         
166         
167         int[] sccPrice=new int[sccs.size()];
168         int[] sccCost=new int[sccs.size()];
169         //将每个强连通分量的price值设为强连通分量中price值最小的顶点的price值
170         for(int i=0;i<sccs.size();i++){
171             sccPrice[i]=Integer.MAX_VALUE;
172             for(int j=0;j<sccs.get(i).size();j++){
173                 //sccs.get(i).get(j) 第i个强连通分量的第j个顶点
174                 if(price[sccs.get(i).get(j)]<sccPrice[i]){
175                     sccPrice[i]=price[sccs.get(i).get(j)];
176                 }
177             }
178         }
179         
180         //对DAG进行拓扑排序
181         ArrayDeque<Integer> topoQueue=new ArrayDeque<>();
182         topoSort(topoQueue, sccEdges, sccs.size());
183         
184         for(int i=0;i<sccs.size();i++)
185             sccCost[i]=sccPrice[i];
186         
187         //topoSort(topoQueue,edges,vexNum);
188         ////依次处理DAG中每个顶点,每个顶点取自身的price值和邻接点的cost值得最小值
189         while(!topoQueue.isEmpty()){
190             int v=topoQueue.poll();
191             for(int i=0;i<sccs.size();i++){
192                 if(sccEdges[v][i]==1 && sccCost[i]<sccCost[v])
193                     sccCost[v]=sccCost[i];
194             }
195         }
196         
197         //visitedN[i] 第i个顶点在第几个强连通分量中
198         for(int i=0;i<vexNum;i++)
199             System.out.println("cost["+i+"]="+sccCost[visitedN[i]]);
200     }
201     
202     //对原图进行深度优先遍历
203     //在汇点强连通部件中对某个顶点进行深度优先遍历则刚好访问该强连通部件的所有顶点
204     private void sccDFS(boolean[] visited,int[] visitedN,int v,List<List<Integer>> sccs,
205             List<Integer> vexs,/*boolean[] isSinkSCC,*/int n){ 
206         sccs.get(n).add(v);
207         vexs.add(v);
208         visitedN[v]=n;
209         for(int i=0;i<vexNum;i++){
210             if(edges[v][i]==1){            
211                 //若遍历到其他强连通分量的顶点说明该强连通分量不是汇点强连通分量
212                 if(visited[i]){        
213                     //i为其他强连通分量的顶点,所以当前强连通分量有一条边指向i所在的强连通分量
214                     sccEdges[n][visitedN[i]]=1;
215                 }else if(visitedN[i]!=n){                
216                     sccDFS(visited,visitedN,i,sccs,vexs,/*isSinkSCC,*/n);
217                 }
218             }
219         }//for
220     }
221     //***********************************************************
222     /*
223      * 对反向图进行深度优先遍历,post值最大的顶点将位于反向图中的一个源点强连通部件,
224      * 也就是原图中的某个汇点连通部件的某个顶点
225      * 按post值从小到大,压入栈中
226      */
227     public void rDFSTraverse(){
228         boolean[] visited=new boolean[vexNum];
229         for(int i=0;i<vexNum;i++){
230             if(!visited[i]){
231                 rDFS(visited,stack,i);
232             }
233         }
234     }        
235     //对反向图做深度优先遍历
236     private void rDFS(boolean[] visited,Stack<Integer> stack,int v){
237         visited[v]=true;
238         for(int i=0;i<vexNum;i++){
239             if(rEdges[v][i]==1 && !visited[i]){
240                 rDFS(visited,stack,i);
241             }
242         }
243         stack.push(v);
244     }
245 }
View Code
原文地址:https://www.cnblogs.com/xiu68/p/7988812.html