The source code and dockerfile for the GSW2024 AI Lab.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

392 lines
15 KiB

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