Language:
C++     Change language:
Pastebin: 115644
Author: Unknown
Subject: Maximum Flow Minimum Cut
Created: 2009-06-09 06:30:11
Download and save
Toggle line numbers
1// Derived from 
2// http://www.aduni.org/courses/algorithms/handouts/Reciation_09.html#25630 
3 
4// For Summer 2002 CSE 2320 Lab 4, the following changes were made to ff.c: 
5//   1. Adjacency lists (sorting, etc.) 
6//   2. Print minimum cut 
7 
8// The Ford-Fulkerson Algorithm in C 
9 
10#include <stdio.h> 
11#include <stdlib.h> 
12// For getrusage() 
13#include <sys/time.h> 
14#include <sys/resource.h> 
15 
16// Basic Definitions 
17 
18#define WHITE 0 
19#define GRAY 1 
20#define BLACK 2 
21#define oo 1000000000 
22 
23// Declarations 
24 
25int n;  // number of nodes 
26int residualEdges;  // number of edges in residual network 
27struct edge { 
28  int tail,head,capacity,flow,inverse; 
29}; 
30typedef struct edge edgeType; 
31edgeType *edgeTab; 
32int *firstEdge;  // Table indicating first in range of edges with a common tail 
33 
34int *color;      // Needed for breadth-first search 
35int *pred;       // Array to store augmenting path 
36int *predEdge;   // edgeTab subscript of edge used to reach vertex i in BFS 
37 
38float CPUtime() 
39
40struct rusage rusage; 
41 
42getrusage(RUSAGE_SELF,&rusage); 
43return rusage.ru_utime.tv_sec+rusage.ru_utime.tv_usec/1000000.0 
44       + rusage.ru_stime.tv_sec+rusage.ru_stime.tv_usec/1000000.0
45
46 
47int min (int x, int y) 
48
49return x<y ? x : y;  // returns minimum of x and y 
50
51 
52// Queue for breadth-first search - not circular. 
53 
54int head,tail; 
55int *q; 
56 
57void enqueue (int x) 
58
59q[tail] = x; 
60tail++; 
61color[x] = GRAY; 
62
63 
64int dequeue () 
65
66int x = q[head]; 
67head++; 
68color[x] = BLACK; 
69return x; 
70
71 
72// Breadth-First Search for an augmenting path 
73 
74int bfs (int start, int target) 
75// Searches for path from start to target. 
76// Returns 1 if found, otherwise 0. 
77
78int u,v,i; 
79 
80for (u=0; u<n; u++) 
81  color[u] = WHITE; 
82head = tail = 0;  // Since q is not circular, it is reinitialized for each BFS 
83enqueue(start); 
84pred[start] = -1
85while (head!=tail) 
86
87  u=dequeue(); 
88  if (u==target) 
89    return 1
90 
91  // Search all adjacent white nodes v. If the residual capacity 
92  // from u to v in the residual network is positive, 
93  // enqueue v. 
94  for (i=firstEdge[u]; i<firstEdge[u+1]; i++) 
95  { 
96    v=edgeTab[i].head; 
97    if (color[v]==WHITE && edgeTab[i].capacity-edgeTab[i].flow>0
98    { 
99      enqueue(v); 
100      pred[v] = u; 
101      predEdge[v]=i; 
102    } 
103  } 
104
105// No augmenting path remains, so a maximum flow and minimum cut 
106// have been found.  Black vertices are in the 
107// source side (S) of the minimum cut, while white vertices are in the 
108// sink side (T). 
109 
110return 0
111
112 
113// Ford-Fulkerson Algorithm 
114 
115int max_flow (int source, int sink) 
116
117int i,j,u; 
118int max_flow; 
119int APcount=0
120 
121color=(int*) malloc(n*sizeof(int)); 
122pred=(int*) malloc(n*sizeof(int)); 
123predEdge=(int*) malloc(n*sizeof(int)); 
124q=(int*) malloc(n*sizeof(int)); 
125if (!color || !pred || !predEdge || !q) 
126
127  printf("malloc failed %d\n",__LINE__); 
128  exit(0); 
129
130 
131// Initialize empty flow. 
132max_flow = 0
133for (i=0; i<residualEdges; i++) 
134  edgeTab[i].flow=0
135 
136// While there exists an augmenting path, 
137// increment the flow along this path. 
138while (bfs(source,sink)) 
139
140  // Determine the amount by which we can increment the flow. 
141  int increment = oo; 
142  APcount++; 
143  for (u=sink; pred[u]!=(-1); u=pred[u]) 
144  { 
145    i=predEdge[u]; 
146    increment = min(increment,edgeTab[i].capacity-edgeTab[i].flow); 
147  } 
148  // Now increment the flow. 
149  for (u=sink; pred[u]!=(-1); u=pred[u]) 
150  { 
151    i = edgeTab[predEdge[u]].inverse; 
152    edgeTab[predEdge[u]].flow += increment; 
153    edgeTab[i].flow -= increment;  // Reverse in residual 
154  } 
155  if (n<=20
156  { 
157    // Path trace 
158    for (u=sink; pred[u]!=(-1); u=pred[u]) 
159      printf("%d<-",u); 
160    printf("%d adds %d incremental flow\n",source,increment); 
161  } 
162  max_flow += increment; 
163
164printf("%d augmenting paths\n",APcount); 
165// No more augmenting paths, so cut is based on reachability from last BFS. 
166if (n<=20
167
168  printf("S side of min-cut:\n"); 
169  for (u=0; u<n; u++) 
170    if (color[u]==BLACK) 
171      printf("%d\n",u); 
172 
173  printf("T side of min-cut:\n"); 
174  for (u=0; u<n; u++) 
175    if (color[u]==WHITE) 
176      printf("%d\n",u); 
177
178 
179free(color); 
180free(pred); 
181free(predEdge); 
182free(q); 
183 
184return max_flow; 
185
186 
187// Reading the input file and organize adjacency lists for residual network. 
188 
189int tailThenHead(const void* xin, const void* yin) 
190// Used in calls to qsort() and bsearch() for read_input_file() 
191
192int result; 
193edgeType *x,*y; 
194 
195x=(edgeType*) xin; 
196y=(edgeType*) yin; 
197result=x->tail - y->tail; 
198if (result!=0
199  return result; 
200else 
201  return x->head - y->head; 
202
203 
204void dumpEdges(int count) 
205
206int i; 
207 
208printf("  i tail head  cap\n"); 
209for (i=0; i<count; i++) 
210  printf("%3d %3d  %3d %5d\n",i,edgeTab[i].tail,edgeTab[i].head, 
211    edgeTab[i].capacity); 
212
213 
214void dumpFinal() 
215
216int i; 
217 
218printf("Initialized residual network:\n"); 
219printf("Vertex firstEdge\n"); 
220for (i=0; i<n; i++) 
221  printf(" %3d    %3d\n",i,firstEdge[i]); 
222printf("=================\n"); 
223printf(" %3d    %3d\n",n,firstEdge[n]); 
224 
225printf("  i tail head  cap  inv\n"); 
226for (i=0; i<residualEdges; i++) 
227  printf("%3d %3d  %3d %5d  %3d\n",i,edgeTab[i].tail,edgeTab[i].head, 
228    edgeTab[i].capacity,edgeTab[i].inverse); 
229
230 
231void read_input_file() 
232
233int tail,head,capacity,i,j; 
234int inputEdges;     // Number of edges in input file. 
235int workingEdges;   // Number of residual network edges initially 
236                    // generated from input file. 
237edgeType work; 
238edgeType *ptr; 
239float startCPU,stopCPU; 
240 
241// read number of nodes and edges 
242scanf("%d %d",&n,&inputEdges); 
243// Table is allocated at worst-case size, since space for inverses is needed. 
244edgeTab=(edgeType*) malloc(2*inputEdges*sizeof(edgeType)); 
245if (!edgeTab) 
246
247  printf("edgeTab malloc failed %d\n",__LINE__); 
248  exit(0); 
249
250// read edges, each with a capacity 
251workingEdges=0
252for (i=0; i<inputEdges; i++) 
253
254  scanf("%d %d %d",&tail,&head,&capacity); 
255  // Test for illegal edge, including incoming to source and outgoing from 
256  // sink. 
257  if (tail<0 || tail>=n-1 || head<1 || head>=n || capacity<=0
258  { 
259    printf("Invalid input %d %d %d at %d\n",tail,head,capacity,__LINE__); 
260    exit(0); 
261  } 
262  // Save input edge 
263  edgeTab[workingEdges].tail=tail; 
264  edgeTab[workingEdges].head=head; 
265  edgeTab[workingEdges].capacity=capacity; 
266  workingEdges++; 
267  // Save inverse of input edge 
268  edgeTab[workingEdges].tail=head; 
269  edgeTab[workingEdges].head=tail; 
270  edgeTab[workingEdges].capacity=0
271  workingEdges++; 
272
273if (n<=20
274
275  printf("Input & inverses:\n"); 
276  dumpEdges(workingEdges); 
277
278 
279// Sort edges to make edges with common tail contiguous in edgeTab, 
280// along with making parallel edges contiguous. 
281// A faster sort is unlikely to speed-up substantially. 
282startCPU=CPUtime(); 
283qsort(edgeTab,workingEdges,sizeof(edgeType),tailThenHead); 
284stopCPU=CPUtime(); 
285printf("qsort CPU %f\n",stopCPU-startCPU); 
286if (n<=20
287
288  printf("Sorted edges:\n"); 
289  dumpEdges(workingEdges); 
290
291 
292// Coalesce parallel edges into a single edge by adding their capacities. 
293residualEdges=0
294for (i=1; i<workingEdges; i++) 
295  if (edgeTab[residualEdges].tail==edgeTab[i].tail 
296  &&  edgeTab[residualEdges].head==edgeTab[i].head) 
297    edgeTab[residualEdges].capacity+=edgeTab[i].capacity;  // || case 
298  else 
299  { 
300    residualEdges++; 
301    edgeTab[residualEdges].tail=edgeTab[i].tail; 
302    edgeTab[residualEdges].head=edgeTab[i].head; 
303    edgeTab[residualEdges].capacity=edgeTab[i].capacity; 
304  } 
305residualEdges++; 
306if (n<=20
307
308  printf("Coalesced edges:\n"); 
309  dumpEdges(residualEdges); 
310
311 
312// Set field in each edgeTab struct to point to inverse 
313startCPU=CPUtime(); 
314for (i=0; i<residualEdges; i++) 
315
316  work.tail=edgeTab[i].head; 
317  work.head=edgeTab[i].tail; 
318  ptr=(edgeType*) bsearch(&work,edgeTab,residualEdges,sizeof(edgeType), 
319    tailThenHead); 
320  if (ptr==NULL
321  { 
322    printf("bsearch %d failed %d\n",i,__LINE__); 
323    exit(0); 
324  } 
325  edgeTab[i].inverse=ptr-edgeTab;  // ptr arithmetic to get subscript 
326
327stopCPU=CPUtime(); 
328printf("set inverses CPU %f\n",stopCPU-startCPU); 
329 
330// For each vertex i, determine first edge in edgeTab with 
331// a tail >= i. 
332firstEdge=(int*) malloc((n+1)*sizeof(int)); 
333if (!firstEdge) 
334
335  printf("malloc failed %d\n",__LINE__); 
336  exit(0); 
337
338j=0
339for (i=0; i<n; i++) 
340
341  firstEdge[i]=j; 
342  // Skip over edges with vertex i as their tail. 
343  for ( ; 
344       j<residualEdges && edgeTab[j].tail==i; 
345       j++) 
346    ; 
347
348firstEdge[n]=residualEdges;  //Sentinel 
349if (n<=20
350  dumpFinal(); 
351
352 
353int main () 
354
355int i,j; 
356float startCPU,stopCPU; 
357 
358read_input_file(); 
359startCPU=CPUtime(); 
360printf("total flow is %d\n",max_flow(0,n-1));  // 0=source, n-1=sink 
361stopCPU=CPUtime(); 
362printf("Ford-Fulkerson time %f\n",stopCPU-startCPU); 
363if (n<=20
364
365  printf("flows along edges:\n"); 
366  for (i=0; i<residualEdges; i++) 
367    if (edgeTab[i].flow>0
368      printf("%d->%d has %d\n",edgeTab[i].tail, 
369        edgeTab[i].head,edgeTab[i].flow); 
370
371free(edgeTab); 
372free(firstEdge); 
373
374 
375 
Download and save
Toggle line numbers
Thread:
[115644] Maximum Flow Minimum Cut by Unknown at 2009-06-09 06:30:11
Tip: Click the line numbers to toggle highliting on that line.

Paste followup:

Language:
Author:
Subject:


    Tabstop:     bigger biggest
Note: You can prefix a line with "@@@" to highlight it.