1. 程式人生 > >Ex 7_17 考慮如下的網絡(其中數字為對應邊的容量)...第十三次作業

Ex 7_17 考慮如下的網絡(其中數字為對應邊的容量)...第十三次作業

n) body ttl 優先 edge images edt -a 存在

技術分享圖片

(a) 利用ford-fulkerson算法即可求出最大流和最小分割。

(b) 剩余網絡為

技術分享圖片

由S可達的頂點為A、B。可達T的頂點為C。

(c) 瓶頸邊有e(A,C),e(B,C)。

(d) 下圖中不包含瓶頸邊。

技術分享圖片

(e) 如果一條邊e(u,v)是瓶頸邊,首先這條邊必須存在原圖中,同時,在殘量圖中存在S到u的路徑並且存在v到T的路徑,所以在殘量圖中增加一條邊e(u,v)後將使最大流的規模增加。首先在殘量圖中從S開始進行一次DFS求出從源點S可以到達的頂點集合W,然後在殘量圖的反向圖中從T開始進行DFS求出可以到達T的頂點集合Y。最後遍歷原圖中的所有邊e(u,v),若uW並且vY,則e(u,v)是一條瓶頸邊。

技術分享圖片
  1 package org.xiu68.ch07.ex13;
  2 
  3 import java.util.ArrayDeque;
  4 import java.util.ArrayList;
  5 import java.util.Arrays;
  6 import java.util.HashSet;
  7 import java.util.Iterator;
  8 
  9 public class Ex7_17 {
 10 
 11     public static void main(String[] args) {
 12         //
TODO Auto-generated method stub 13 int[][] c=new int[][]{ 14 {0,7,6,0,0,0}, 15 {0,0,0,4,2,0}, 16 {0,0,0,2,3,0}, 17 {0,0,0,0,0,9}, 18 {0,0,0,0,0,5}, 19 {0,0,0,0,0,0} 20 }; 21 String[] vexs=new String[]{"S","A","B","C","D","T"};
22 MGraph<String> m1=new MGraph<String>(c, vexs); 23 m1.fordFulkerson(0, 5); 24 } 25 26 } 27 28 class MGraph<T>{ 29 private int[][] c; //容量矩陣 30 private int[][] e; //殘量矩陣 31 private int[][] f; //當前流矩陣 32 private int vexNum; //頂點數量 33 private String[] vexs; //頂點表 34 35 public MGraph(int[][] c,String[] vexs){ 36 this.c=c; 37 this.vexNum=c.length; 38 this.e=new int[vexNum][vexNum]; 39 this.f=new int[vexNum][vexNum]; 40 this.vexs=vexs; 41 42 //剛開始時殘量矩陣等於容量矩陣 43 for(int i=0;i<vexNum;i++){ 44 System.arraycopy(c[i], 0, e[i], 0, c[i].length); 45 } 46 47 } 48 49 //fordFulkerson算法 50 public void fordFulkerson(int s,int t){ 51 int[] route=new int[vexNum]; //s到t的路徑數組,route[i]表示i的前一個頂點 52 53 while(bfs(s,t,route)){ //若還能找到一條路徑 54 55 //尋找路徑中流最小的邊的大小(在殘量矩陣中) 56 int min=Integer.MAX_VALUE; 57 int tail=t; 58 int head=route[t]; 59 60 while(head!=-1){ 61 if(e[head][tail]<min){ 62 min=e[head][tail]; 63 } 64 tail=head; 65 head=route[head]; 66 } 67 68 //更新當前流矩陣和殘量矩陣 69 int tail1=t; 70 int head1=route[tail1]; 71 while(head1!=-1){ 72 //更新當前流矩陣 73 if(c[head1][tail1]!=0){ 74 f[head1][tail1]+=min; //容量矩陣中存在邊,增加head1到tail1的流的大小為min 75 }else{ 76 f[head1][tail1]-=min; //容量矩陣中不存在邊,撤銷head1到tail1的流的大小為min 77 } 78 //更新殘量矩陣 79 e[head1][tail1]-=min; //head1到tail1的流量減少min 80 e[tail1][head1]+=min; //tail1到head1的流量增加min 81 82 tail1=head1; 83 head1=route[head1]; 84 }//while 85 //route=new int[vexNum]; 86 Arrays.fill(route, 0); //初始化路徑數組 87 }//while 還能找到一條s到t的路徑 88 89 //輸出最大流 90 int maxFlow=0; 91 for(int i=0;i<vexNum;i++) //最大流為 當前流矩陣中 從s流出的量 92 maxFlow+=f[s][i]; 93 System.out.println("最大流為:"+maxFlow); 94 95 //輸出最小割 96 System.out.print("最小割為(集合S):"); 97 HashSet<Integer> cut=cut(s); 98 for(Iterator<Integer> iter=cut.iterator();iter.hasNext();){ 99 System.out.print(vexs[iter.next()]+" "); 100 } 101 System.out.println(); 102 103 //輸出瓶頸邊 104 System.out.println("瓶頸邊有"); 105 HashSet<Edge> bottleneckEdgeSet=bottleneckEdge(s,t); 106 for(Iterator<Edge> be=bottleneckEdgeSet.iterator();be.hasNext();){ 107 Edge ed=be.next(); 108 System.out.print("e("+vexs[ed.getHead()]+","+vexs[ed.getTail()]+") "); 109 } 110 } 111 112 //廣度優先搜索在殘量圖e中尋找s到t的路徑 113 public boolean bfs(int s,int t,int[] route){ 114 boolean[] visited=new boolean[vexNum]; //訪問數組 115 visited[s]=true; 116 117 ArrayDeque<Integer> queue=new ArrayDeque<>(); 118 route[s]=-1; //設s的前一個頂點為-1 119 120 for(int i=0;i<vexNum;i++){ 121 if(e[s][i]!=0 && !visited[i]){ //在殘量矩陣中s到i存在一條路徑 122 queue.add(i); 123 route[i]=s; 124 visited[i]=true; 125 } 126 } 127 128 while(!queue.isEmpty()){ 129 int middleVex=queue.poll(); 130 if(middleVex==t){ 131 return true; 132 }else{ 133 for(int i=0;i<vexNum;i++){ 134 if(e[middleVex][i]!=0 && !visited[i]){ 135 queue.add(i); 136 route[i]=middleVex; 137 visited[i]=true; 138 } 139 } 140 } 141 }//while 142 return false; 143 } 144 145 //求最小割 146 //在殘量矩陣中,從s開始做一次搜索,從s能達到的所有的頂點都屬於集合S 147 public HashSet<Integer> cut(int s){ 148 boolean[] visited=new boolean[vexNum]; 149 HashSet<Integer> cut=new HashSet<>(); //保存最小割,集合S 150 dfs(e,visited,cut,s); 151 return cut; 152 } 153 //求瓶頸邊 154 public HashSet<Edge> bottleneckEdge(int s,int t){ 155 156 HashSet<Integer> w=new HashSet<>(); //從頂點S可以到達的頂點集合 157 boolean[] visitedS=new boolean[vexNum]; 158 dfs(e,visitedS,w,s); //從頂點s開始進行深度優先搜索,求從頂點S可以到達的頂點集合 159 160 161 //求殘量圖的反向圖 162 int[][] reverseE=new int[vexNum][vexNum]; 163 for(int i=0;i<vexNum;i++){ 164 for(int j=i+1;j<vexNum;j++){ 165 reverseE[i][j]=e[j][i]; 166 reverseE[j][i]=e[i][j]; 167 } 168 } 169 HashSet<Integer> y=new HashSet<>(); //從頂點S可以到達的頂點集合 170 boolean[] visitedT=new boolean[vexNum]; 171 dfs(reverseE,visitedT,y,t); //從頂點t開始進行深度優先搜索,求從頂點T可以到達的頂點集合 172 173 174 HashSet<Edge> bottleneckEdgeSet=new HashSet<>(); 175 //遍歷原圖中的所有邊e(u,v),求u屬於集合w,v屬於集合y的邊 176 for(int i=0;i<vexNum;i++){ 177 for(int j=0;j<vexNum;j++){ 178 if(c[i][j]!=0 && w.contains(i) && y.contains(j)){ 179 bottleneckEdgeSet.add(new Edge(i,j)); 180 } 181 } 182 } 183 return bottleneckEdgeSet; 184 } 185 //深度優先搜索,記錄搜索到的所有頂點 186 private void dfs(int[][] edges,boolean[] visited,HashSet<Integer> set,int v){ 187 set.add(v); 188 visited[v]=true; 189 for(int i=0;i<vexNum;i++){ 190 if(edges[v][i]!=0 && !visited[i]){ 191 dfs(edges,visited,set,i); 192 } 193 } 194 } 195 } 196 197 class Edge{ 198 private int head; //邊的頭 199 private int tail; //邊的尾 200 public Edge(int head, int tail) { 201 super(); 202 this.head = head; 203 this.tail = tail; 204 } 205 public int getHead() { 206 return head; 207 } 208 public void setHead(int head) { 209 this.head = head; 210 } 211 public int getTail() { 212 return tail; 213 } 214 public void setTail(int tail) { 215 this.tail = tail; 216 } 217 218 }
View Code

Ex 7_17 考慮如下的網絡(其中數字為對應邊的容量)...第十三次作業