Minimum cut

Concepts

Cut

For a flow network G=(V,E)G=(V,E), a cut is a partition of vertices: partition all vertices into two sets SS and T=V−ST=V-S, where the source s∈Ss\in S and the sink t∈Tt\in T.

Capacity of a cut

The capacity (S,T)(S,T) of a cut c(S,T)c(S,T) is the sum of the capacities of all edges from SS to TT, namely c(S,T)=∑u∈S,v∈Tc(u,v)c(S,T)=\sum_{u\in S,v\in T}c(u,v). We may also write c(s,t)c(s,t) for c(S,T)c(S,T).

Minimum cut

A minimum cut is a cut (S,T)(S,T) whose capacity c(S,T)c(S,T) is minimum.

Proof

Max-flow min-cut theorem

See the section on the max-flow min-cut theorem on the maximum flow page.

Code

Minimum cut

By the max-flow min-cut theorem, we can directly obtain the following code:

Reference implementation
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>

constexpr int N = 1e4 + 5, M = 2e5 + 5;
int n, m, s, t, tot = 1, lnk[N], ter[M], nxt[M], val[M], dep[N], cur[N];

void add(int u, int v, int w) {
  ter[++tot] = v, nxt[tot] = lnk[u], lnk[u] = tot, val[tot] = w;
}

void addedge(int u, int v, int w) { add(u, v, w), add(v, u, 0); }

int bfs(int s, int t) {
  memset(dep, 0, sizeof(dep));
  memcpy(cur, lnk, sizeof(lnk));
  std::queue<int> q;
  q.push(s), dep[s] = 1;
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    for (int i = lnk[u]; i; i = nxt[i]) {
      int v = ter[i];
      if (val[i] && !dep[v]) q.push(v), dep[v] = dep[u] + 1;
    }
  }
  return dep[t];
}

int dfs(int u, int t, int flow) {
  if (u == t) return flow;
  int ans = 0;
  for (int &i = cur[u]; i && ans < flow; i = nxt[i]) {
    int v = ter[i];
    if (val[i] && dep[v] == dep[u] + 1) {
      int x = dfs(v, t, std::min(val[i], flow - ans));
      if (x) val[i] -= x, val[i ^ 1] += x, ans += x;
    }
  }
  if (ans < flow) dep[u] = -1;
  return ans;
}

int dinic(int s, int t) {
  int ans = 0;
  while (bfs(s, t)) {
    int x;
    while ((x = dfs(s, t, 1 << 30))) ans += x;
  }
  return ans;
}

int main() {
  scanf("%d%d%d%d", &n, &m, &s, &t);
  while (m--) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addedge(u, v, w);
  }
  printf("%d\n", dinic(s, t));
  return 0;
}

Partition

Starting DFS from the source ss and traversing edges with residual capacity greater than 00 each time, we can find all vertices in the set SS.

void dfs(int u) {
  vis[u] = 1;
  for (int i = lnk[u]; i; i = nxt[i]) {
    int v = ter[i];
    if (!vis[v] && val[i]) dfs(v);
  }
}

Number of cut edges

If the number of cut edges must be minimized subject to a minimum cut, first find a minimum cut, change the capacities of edges that are not saturated to ∞\infty and those that are saturated to 11, and run minimum cut again. If there is no minimum-cut constraint, simply set every edge capacity to 11 and find a minimum cut.

Problem model 1

There are nn items and two sets A,BA,B. Not putting an item into AA costs aia_i, and not putting it into BB costs bib_i. There are also constraints of the form ui,vi,wiu_i,v_i,w_i, meaning that if uiu_i and viv_i are not in the same set, the cost is wiw_i. Every item must belong to exactly one set; find the minimum cost.

This is a classic choose-one-of-two minimum-cut problem. Use a source ss and sink tt for the two sets; for vertex ii, add an edge of capacity ss from aia_i and an edge of capacity tt to bib_i. For a constraint u,v,wu,v,w, add a bidirectional edge of capacity u,vu,v between ww and $v.

When the source and sink are disconnected, the vertices on each side represent the choices of the two sets. Cutting an edge incident to ss or tt means not putting the item in AA or BB; cutting an edge between items means that the two items are not put in the same set.

The minimum cut is the minimum cost.

Problem model 2

A maximum-weight closure problem gives a directed graph in which every vertex has a weight (positive, negative, or 00). Choose a subgraph with maximum total weight such that every successor of every vertex in the subgraph is also in the subgraph.

Construct a super-source ss and super-sink tt. If vertex uu has positive weight, add a directed edge from ss to uu whose capacity is its weight; if uu has negative weight, add a directed edge from uu to tt whose capacity is the opposite of its weight. Set the capacities of all original edges to ∞\infty. Run maximum flow; the sum of all positive weights minus the maximum flow is the answer.

We prove several small claims:

  1. Every valid subgraph corresponds to a cut in the flow network. A cut divides the network into two parts, and the part connected to ss has no edge directed to the other part, so it satisfies the condition above. This correspondence is an if and only if.
  2. Every edge removed by a minimum cut must be incident to either ss or tt. Otherwise its capacity is ∞\infty, so it cannot belong to a minimum cut.
  3. The weight sum of the chosen subgraph == the sum of all positive weights −- the sum of the positive weights of unchosen vertices ++ the sum of the negative weights of chosen vertices. When a positive-weight vertex is not chosen, its edge to ss is cut; when a negative-weight vertex is chosen, its edge to tt is cut. The sum of the capacities of the cut edges is the cut capacity. Thus the expression becomes: weight sum == sum of all positive weights −- cut capacity.
  4. Therefore, the maximum weight sum == the sum of all positive weights −- the minimum cut == the sum of all positive weights −- the maximum flow.

Exercises

This content comes from OI Wiki: Minimum cut. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.