1 package org.xiu68.exp.exp10;
2
3 import java.util.ArrayDeque;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6
7 public class Exp10_2 {
8 //实现Ford-Fulkerson算法,求出给定图中从源点s到汇点t的最大流,并输出最小割。
9 public static void main(String[] args) {
10 // TODO Auto-generated method stub
11 int[][] c=new int[][]{
12 {0,1,1,0},
13 {0,0,1,1},
14 {0,0,0,1},
15 {0,0,0,0}
16 };
17 MGraph1 m1=new MGraph1(c);
18 m1.fordFulkerson(0, 3);
19
20 int[][] c1=new int[][]{
21 {0,3,3,4,0,0,0},
22 {0,0,0,0,2,0,0},
23 {0,1,0,0,1,0,0},
24 {0,0,0,0,0,5,0},
25 {0,0,0,1,0,1,2},
26 {0,0,0,0,0,0,5},
27 {0,0,0,0,0,0,0}
28 };
29 MGraph1 m2=new MGraph1(c1);
30 m2.fordFulkerson(0, 6);
31 }
32 }
33
34 class MGraph1{
35 private int[][] c; //容量矩阵
36 private int[][] e; //残量矩阵
37 private int[][] f; //当前流矩阵
38 private int vexNum; //顶点数量
39
40 public MGraph1(int[][] c){
41 this.c=c;
42 this.vexNum=c.length;
43 this.e=new int[vexNum][vexNum];
44 this.f=new int[vexNum][vexNum];
45
46 //刚开始时残量矩阵等于容量矩阵
47 for(int i=0;i<vexNum;i++){
48 System.arraycopy(c[i], 0, e[i], 0, c[i].length);
49 }
50
51 }
52 //fordFulkerson算法
53 public void fordFulkerson(int s,int t){
54 int[] route=new int[vexNum]; //s到t的路径数组,route[i]表示i的前一个顶点
55
56 while(bfs(s,t,route)){ //若还能找到一条路径
57
58 //寻找路径中流最小的边的大小(在残量矩阵中)
59 int min=Integer.MAX_VALUE;
60 int tail=t;
61 int head=route[t];
62
63 while(head!=-1){
64 if(e[head][tail]<min){
65 min=e[head][tail];
66 }
67 tail=head;
68 head=route[head];
69 }
70
71 //更新当前流矩阵和残量矩阵
72 int tail1=t;
73 int head1=route[tail1];
74 while(head1!=-1){
75 //更新当前流矩阵
76 if(c[head1][tail1]!=0){
77 f[head1][tail1]+=min; //容量矩阵中存在边,增加head1到tail1的流的大小为min
78 }else{
79 f[head1][tail1]-=min; //容量矩阵中不存在边,撤销head1到tail1的流的大小为min
80 }
81 //更新残量矩阵
82 e[head1][tail1]-=min; //head1到tail1的流量减少min
83 e[tail1][head1]+=min; //tail1到head1的流量增加min
84
85 tail1=head1;
86 head1=route[head1];
87 }//while
88 //route=new int[vexNum];
89 Arrays.fill(route, 0); //初始化路径数组
90 }//while 还能找到一条s到t的路径
91
92 int maxFlow=0;
93 for(int i=0;i<vexNum;i++) //最大流为 当前流矩阵中 从s流出的量
94 maxFlow+=f[s][i];
95 System.out.println("最大流为:"+maxFlow);
96
97
98 System.out.print("最小割为(集合S):");
99 ArrayList<Integer> cut=cut(s);
100 for(int i=0;i<cut.size();i++)
101 System.out.print(cut.get(i)+" ");
102 System.out.println();
103
104 }
105
106 //广度优先搜索在残量图e中寻找s到t的路径
107 public boolean bfs(int s,int t,int[] route){
108 boolean[] visited=new boolean[vexNum]; //访问数组
109 visited[s]=true;
110
111 ArrayDeque<Integer> queue=new ArrayDeque<>();
112 route[s]=-1; //设s的前一个顶点为-1
113
114 for(int i=0;i<vexNum;i++){
115 if(e[s][i]!=0 && !visited[i]){ //在残量矩阵中s到i存在一条路径
116 queue.add(i);
117 route[i]=s;
118 visited[i]=true;
119 }
120 }
121
122 while(!queue.isEmpty()){
123 int middleVex=queue.poll();
124 if(middleVex==t){
125 return true;
126 }else{
127 for(int i=0;i<vexNum;i++){
128 if(e[middleVex][i]!=0 && !visited[i]){
129 queue.add(i);
130 route[i]=middleVex;
131 visited[i]=true;
132 }
133 }
134 }
135 }//while
136 return false;
137 }
138
139 //求最小割
140 //在残量矩阵中,从s开始做一次搜索,从s能达到的所有的顶点都属于集合S
141 public ArrayList<Integer> cut(int s){
142 boolean[] visited=new boolean[vexNum];
143 ArrayList<Integer> cut=new ArrayList<>(); //保存最小割,集合S
144 dfs(visited,cut,s);
145 return cut;
146 }
147 //深度优先搜索
148 private void dfs(boolean[] visited,ArrayList<Integer> cut,int v){
149 cut.add(v);
150 visited[v]=true;
151 for(int i=0;i<vexNum;i++){
152 if(e[v][i]!=0 && !visited[i]){
153 dfs(visited,cut,i);
154 }
155 }
156 }
157 }