1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
|
/* mincut.c */
/* Written by Andrew Makhorin <mao@gnu.org>, October 2015. */
#include <limits.h>
#include "maxflow.h"
#include "mincut.h"
#include "misc.h"
/***********************************************************************
* NAME
*
* min_cut - find min cut in undirected capacitated network
*
* SYNOPSIS
*
* #include "mincut.h"
* int min_cut(int nn, int ne, const int beg[], const int end[],
* const cap[], int cut[]);
*
* DESCRIPTION
*
* This routine finds min cut in a given undirected network.
*
* The undirected capacitated network is specified by the parameters
* nn, ne, beg, end, and cap. The parameter nn specifies the number of
* vertices (nodes), nn >= 2, and the parameter ne specifies the number
* of edges, ne >= 0. The network edges are specified by triplets
* (beg[k], end[k], cap[k]) for k = 1, ..., ne, where beg[k] < end[k]
* are numbers of the first and second nodes of k-th edge, and
* cap[k] > 0 is a capacity of k-th edge. Loops and multiple edges are
* not allowed.
*
* Let V be the set of nodes of the network and let W be an arbitrary
* non-empty proper subset of V. A cut associated with the subset W is
* a subset of all the edges, one node of which belongs to W and other
* node belongs to V \ W. The capacity of a cut (W, V \ W) is the sum
* of the capacities of all the edges, which belong to the cut. Minimal
* cut is a cut, whose capacity is minimal.
*
* On exit the routine stores flags of nodes v[i], i = 1, ..., nn, to
* locations cut[i], where cut[i] = 1 means that v[i] belongs to W and
* cut[i] = 0 means that v[i] belongs to V \ W, where W corresponds to
* the minimal cut found.
*
* RETURNS
*
* The routine returns the capacity of the min cut found. */
int min_cut(int nn, int ne, const int beg[/*1+ne*/],
const int end[/*1+ne*/], const cap[/*1+ne*/], int cut[/*1+nn*/])
{ int k;
/* sanity checks */
xassert(nn >= 2);
xassert(ne >= 0);
for (k = 1; k <= ne; k++)
{ xassert(1 <= beg[k] && beg[k] < end[k] && end[k] <= nn);
xassert(cap[k] > 0);
}
/* find min cut */
return min_cut_sw(nn, ne, beg, end, cap, cut);
}
/***********************************************************************
* NAME
*
* min_st_cut - find min (s,t)-cut for known max flow
*
* SYNOPSIS
*
* #include "mincut.h"
*
* DESCRIPTION
*
* This routine finds min (s,t)-cut in a given undirected network that
* corresponds to a known max flow from s to t in the network.
*
* Parameters nn, ne, beg, end, and cap specify the network in the same
* way as for the routine min_cut (see above).
*
* Parameters s and t specify, resp., the number of the source node
* and the number of the sink node, s != t, for which the min (s,t)-cut
* has to be found.
*
* Parameter x specifies the known max flow from s to t in the network,
* where locations x[1], ..., x[ne] contains elementary flow thru edges
* of the network (positive value of x[k] means that the elementary
* flow goes from node beg[k] to node end[k], and negative value means
* that the flow goes in opposite direction).
*
* This routine splits the set of nodes V of the network into two
* non-empty subsets V(s) and V(t) = V \ V(s), where the source node s
* belongs to V(s), the sink node t belongs to V(t), and all edges, one
* node of which belongs to V(s) and other one belongs to V(t), are
* saturated (that is, x[k] = +cap[k] or x[k] = -cap[k]).
*
* On exit the routine stores flags of the nodes v[i], i = 1, ..., nn,
* to locations cut[i], where cut[i] = 1 means that v[i] belongs to V(s)
* and cut[i] = 0 means that v[i] belongs to V(t) = V \ V(s).
*
* RETURNS
*
* The routine returns the capacity of min (s,t)-cut, which is the sum
* of the capacities of all the edges, which belong to the cut. (Note
* that due to theorem by Ford and Fulkerson this value is always equal
* to corresponding max flow.)
*
* ALGORITHM
*
* To determine the set V(s) the routine simply finds all nodes, which
* can be reached from the source node s via non-saturated edges. The
* set V(t) is determined as the complement V \ V(s). */
int min_st_cut(int nn, int ne, const int beg[/*1+ne*/],
const int end[/*1+ne*/], const int cap[/*1+ne*/], int s, int t,
const int x[/*1+ne*/], int cut[/*1+nn*/])
{ int i, j, k, p, q, temp, *head1, *next1, *head2, *next2, *list;
/* head1[i] points to the first edge with beg[k] = i
* next1[k] points to the next edge with the same beg[k]
* head2[i] points to the first edge with end[k] = i
* next2[k] points to the next edge with the same end[k] */
head1 = xalloc(1+nn, sizeof(int));
head2 = xalloc(1+nn, sizeof(int));
next1 = xalloc(1+ne, sizeof(int));
next2 = xalloc(1+ne, sizeof(int));
for (i = 1; i <= nn; i++)
head1[i] = head2[i] = 0;
for (k = 1; k <= ne; k++)
{ i = beg[k], next1[k] = head1[i], head1[i] = k;
j = end[k], next2[k] = head2[j], head2[j] = k;
}
/* on constructing the set V(s) list[1], ..., list[p-1] contain
* nodes, which can be reached from source node and have been
* visited, and list[p], ..., list[q] contain nodes, which can be
* reached from source node but havn't been visited yet */
list = xalloc(1+nn, sizeof(int));
for (i = 1; i <= nn; i++)
cut[i] = 0;
p = q = 1, list[1] = s, cut[s] = 1;
while (p <= q)
{ /* pick next node, which is reachable from the source node and
* has not visited yet, and visit it */
i = list[p++];
/* walk through edges with beg[k] = i */
for (k = head1[i]; k != 0; k = next1[k])
{ j = end[k];
xassert(beg[k] == i);
/* from v[i] we can reach v[j], if the elementary flow from
* v[i] to v[j] is non-saturated */
if (cut[j] == 0 && x[k] < +cap[k])
list[++q] = j, cut[j] = 1;
}
/* walk through edges with end[k] = i */
for (k = head2[i]; k != 0; k = next2[k])
{ j = beg[k];
xassert(end[k] == i);
/* from v[i] we can reach v[j], if the elementary flow from
* v[i] to v[j] is non-saturated */
if (cut[j] == 0 && x[k] > -cap[k])
list[++q] = j, cut[j] = 1;
}
}
/* sink cannot belong to V(s) */
xassert(!cut[t]);
/* free working arrays */
xfree(head1);
xfree(head2);
xfree(next1);
xfree(next2);
xfree(list);
/* compute capacity of the minimal (s,t)-cut found */
temp = 0;
for (k = 1; k <= ne; k++)
{ i = beg[k], j = end[k];
if (cut[i] && !cut[j] || !cut[i] && cut[j])
temp += cap[k];
}
/* return to the calling program */
return temp;
}
/***********************************************************************
* NAME
*
* min_cut_sw - find min cut with Stoer and Wagner algorithm
*
* SYNOPSIS
*
* #include "mincut.h"
* int min_cut_sw(int nn, int ne, const int beg[], const int end[],
* const cap[], int cut[]);
*
* DESCRIPTION
*
* This routine find min cut in a given undirected network with the
* algorithm proposed by Stoer and Wagner (see references below).
*
* Parameters of this routine have the same meaning as for the routine
* min_cut (see above).
*
* RETURNS
*
* The routine returns the capacity of the min cut found.
*
* ALGORITHM
*
* The basic idea of Stoer&Wagner algorithm is the following. Let G be
* a capacitated network, and G(s,t) be a network, in which the nodes s
* and t are merged into one new node, loops are deleted, but multiple
* edges are retained. It is obvious that a minimum cut in G is the
* minimum of two quantities: the minimum cut in G(s,t) and a minimum
* cut that separates s and t. This allows to find a minimum cut in the
* original network solving at most nn max flow problems.
*
* REFERENCES
*
* M. Stoer, F. Wagner. A Simple Min Cut Algorithm. Algorithms, ESA'94
* LNCS 855 (1994), pp. 141-47.
*
* J. Cheriyan, R. Ravi. Approximation Algorithms for Network Problems.
* Univ. of Waterloo (1998), p. 147. */
int min_cut_sw(int nn, int ne, const int beg[/*1+ne*/],
const int end[/*1+ne*/], const cap[/*1+ne*/], int cut[/*1+nn*/])
{ int i, j, k, min_cut, flow, temp, *head1, *next1, *head2, *next2;
int I, J, K, S, T, DEG, NV, NE, *HEAD, *NEXT, *NUMB, *BEG, *END,
*CAP, *X, *ADJ, *SUM, *CUT;
/* head1[i] points to the first edge with beg[k] = i
* next1[k] points to the next edge with the same beg[k]
* head2[i] points to the first edge with end[k] = i
* next2[k] points to the next edge with the same end[k] */
head1 = xalloc(1+nn, sizeof(int));
head2 = xalloc(1+nn, sizeof(int));
next1 = xalloc(1+ne, sizeof(int));
next2 = xalloc(1+ne, sizeof(int));
for (i = 1; i <= nn; i++)
head1[i] = head2[i] = 0;
for (k = 1; k <= ne; k++)
{ i = beg[k], next1[k] = head1[i], head1[i] = k;
j = end[k], next2[k] = head2[j], head2[j] = k;
}
/* an auxiliary network used in the algorithm is resulted from
* the original network by merging some nodes into one supernode;
* all variables and arrays related to this auxiliary network are
* denoted in CAPS */
/* HEAD[I] points to the first node of the original network that
* belongs to the I-th supernode
* NEXT[i] points to the next node of the original network that
* belongs to the same supernode as the i-th node
* NUMB[i] is a supernode, which the i-th node belongs to */
/* initially the auxiliary network is equivalent to the original
* network, i.e. each supernode consists of one node */
NV = nn;
HEAD = xalloc(1+nn, sizeof(int));
NEXT = xalloc(1+nn, sizeof(int));
NUMB = xalloc(1+nn, sizeof(int));
for (i = 1; i <= nn; i++)
HEAD[i] = i, NEXT[i] = 0, NUMB[i] = i;
/* number of edges in the auxiliary network is never greater than
* in the original one */
BEG = xalloc(1+ne, sizeof(int));
END = xalloc(1+ne, sizeof(int));
CAP = xalloc(1+ne, sizeof(int));
X = xalloc(1+ne, sizeof(int));
/* allocate some auxiliary arrays */
ADJ = xalloc(1+nn, sizeof(int));
SUM = xalloc(1+nn, sizeof(int));
CUT = xalloc(1+nn, sizeof(int));
/* currently no min cut is found so far */
min_cut = INT_MAX;
/* main loop starts here */
while (NV > 1)
{ /* build the set of edges of the auxiliary network */
NE = 0;
/* multiple edges are not allowed in the max flow algorithm,
* so we can replace each multiple edge, which is the result
* of merging nodes into supernodes, by a single edge, whose
* capacity is the sum of capacities of particular edges;
* these summary capacities will be stored in the array SUM */
for (I = 1; I <= NV; I++)
SUM[I] = 0.0;
for (I = 1; I <= NV; I++)
{ /* DEG is number of single edges, which connects I-th
* supernode and some J-th supernode, where I < J */
DEG = 0;
/* walk thru nodes that belong to I-th supernode */
for (i = HEAD[I]; i != 0; i = NEXT[i])
{ /* i-th node belongs to I-th supernode */
/* walk through edges with beg[k] = i */
for (k = head1[i]; k != 0; k = next1[k])
{ j = end[k];
/* j-th node belongs to J-th supernode */
J = NUMB[j];
/* ignore loops and edges with I > J */
if (I >= J)
continue;
/* add an edge that connects I-th and J-th supernodes
* (if not added yet) */
if (SUM[J] == 0.0)
ADJ[++DEG] = J;
/* sum up the capacity of the original edge */
xassert(cap[k] > 0.0);
SUM[J] += cap[k];
}
/* walk through edges with end[k] = i */
for (k = head2[i]; k != 0; k = next2[k])
{ j = beg[k];
/* j-th node belongs to J-th supernode */
J = NUMB[j];
/* ignore loops and edges with I > J */
if (I >= J)
continue;
/* add an edge that connects I-th and J-th supernodes
* (if not added yet) */
if (SUM[J] == 0.0)
ADJ[++DEG] = J;
/* sum up the capacity of the original edge */
xassert(cap[k] > 0.0);
SUM[J] += cap[k];
}
}
/* add single edges connecting I-th supernode with other
* supernodes to the auxiliary network; restore the array
* SUM for subsequent use */
for (K = 1; K <= DEG; K++)
{ NE++;
xassert(NE <= ne);
J = ADJ[K];
BEG[NE] = I, END[NE] = J, CAP[NE] = SUM[J];
SUM[J] = 0.0;
}
}
/* choose two arbitrary supernodes of the auxiliary network,
* one of which is the source and other is the sink */
S = 1, T = NV;
/* determine max flow from S to T */
flow = max_flow(NV, NE, BEG, END, CAP, S, T, X);
/* if the min cut that separates supernodes S and T is less
* than the currently known, remember it */
if (min_cut > flow)
{ min_cut = flow;
/* find min (s,t)-cut in the auxiliary network */
temp = min_st_cut(NV, NE, BEG, END, CAP, S, T, X, CUT);
/* (Ford and Fulkerson insist on this) */
xassert(flow == temp);
/* build corresponding min cut in the original network */
for (i = 1; i <= nn; i++) cut[i] = CUT[NUMB[i]];
/* if the min cut capacity is zero (i.e. the network has
* unconnected components), the search can be prematurely
* terminated */
if (min_cut == 0)
break;
}
/* now merge all nodes of the original network, which belong
* to the supernodes S and T, into one new supernode; this is
* attained by carrying all nodes from T to S (for the sake of
* convenience T should be the last supernode) */
xassert(T == NV);
/* assign new references to nodes from T */
for (i = HEAD[T]; i != 0; i = NEXT[i])
NUMB[i] = S;
/* find last entry in the node list of S */
i = HEAD[S];
xassert(i != 0);
while (NEXT[i] != 0)
i = NEXT[i];
/* and attach to it the node list of T */
NEXT[i] = HEAD[T];
/* decrease number of nodes in the auxiliary network */
NV--;
}
/* free working arrays */
xfree(HEAD);
xfree(NEXT);
xfree(NUMB);
xfree(BEG);
xfree(END);
xfree(CAP);
xfree(X);
xfree(ADJ);
xfree(SUM);
xfree(CUT);
xfree(head1);
xfree(head2);
xfree(next1);
xfree(next2);
/* return to the calling program */
return min_cut;
}
/* eof */
|