Stoer–Wagner Algorithm

Definition

Because the definition of source and sink has been removed, we need to redefine the concept of a cut.

(In fact, the definition of a cut in the network-flow context differs from that on Wikipedia; because the cuts most commonly encountered are minimum-cut problems with a source and a sink, this terminology has become conventional.)

Cut

A set of edges whose removal makes a flow network no longer connected (that is, splits it into two subgraphs) is called a cut of the graph.

In other words: in an undirected graph G=(V,E)G = (V, E), let CC be a set of edges in graph GG. If deleting from GG all edges in CC makes GG disconnected, then CC is called a cut of GG.

Minimum-cut problem with a source and a sink

Same as the definition in minimum cut.

Minimum-cut problem without a source or a sink

A cut whose edges have the minimum total weight. It is also called the global minimum cut.

Clearly, the complexity of directly running a network flow algorithm is too high.


Stoer–Wagner Algorithm

Introduction

The Stoer–Wagner algorithm was proposed in 1995 by Mechthild Stoer and Frank Wagner. It solves the global minimum-cut problem on undirected graphs with positive edge weights by recursively contracting vertices.

Properties

The time complexity is O(∣V∣∣E∣+∣V∣2log⁡∣V∣)O(|V||E| + |V|^{2}\log|V|), which is generally approximated as O(∣V∣3)O(|V|^3).

Its implementation is based on the following basic fact: let graph GG contain any two vertices S,TS, T. Then for graph GG, any cut CC either has S,TS, T in the same connected component, or CC is an S−T{S-T} cut.

Procedure

  1. Choose any two vertices in graph GG, namely s,ts, t, use them as the source and sink, and find graph GG's S−TS-T minimum cut (called a cut of phase), then update the current answer.
  2. “Contract” vertices s,ts, t. If graph GG has ∣V∣|V| greater than 11, return to the first step.
  3. Output the minimum of all cuts of phase.

To contract vertices s,ts, t: remove the edge between s,ts, t, namely (s,t)(s, t). For any vertex in G∖{s,t}G \setminus \{s, t\}, say kk, remove (t,k)(t, k) and add its edge weight d(t,k)d(t, k) to d(s,k)d(s, k).

Explanation: if s,ts, t are in the same connected component, consider G∖{s,t}G \setminus \{s, t\} and a vertex kk in it. If (k,s)∈Cmin⁡(k, s) \in C_{\min}, then (k,t)∈Cmin⁡(k, t) \in C_{\min} must also hold; otherwise, since s,ts, t are connected, k,tk, t are connected, which would make s,ks, k lie in the same connected component, and then C=Cmin⁡∖{(t,k)}C = C_{\min} \setminus \{(t, k)\} would be better than Cmin⁡C_{\min}. The converse is analogous. Therefore, s,ts, t can be regarded as one vertex.

Step 1 considers the case where s,ts,t are not in the same connected component, and step 2 considers the remaining case. Since each execution of step 2 decreases ∣V∣|V| by 11, the algorithm terminates after ∣V∣−1|V| - 1 executions.

Finding the S-T minimum cut

(Clearly, this is not network flow.)

Suppose that after several contractions the current graph is G′=(V′,E′)G'=(V', E'), and we execute step 1.

We construct a set AA, initially setting A=∅A = \varnothing.

At each step, among all vertices in V′V', we add a vertex satisfying i∉Ai \notin A and maximizing the weight function w(A,i)w(A, i) to AA, until ∣A∣=∣V′∣|A| = |V'|.

The weight function is defined as follows:

w(A,i)=∑j∈Ad(i,j)w(A, i) = \sum_{j \in A} d(i, j)

(If (i,j)∉E′(i, j) \notin E', then d(i,j)=0d(i, j) = 0.)

It is easy to see that the order in which all vertices are added to AA is fixed. Let ord⁡(i)\operatorname{ord}(i) denote the vertex added in position ii in AA, and let t=ord⁡(∣V′∣)t = \operatorname{ord}(|V'|); let pos⁡(v)\operatorname{pos}(v) denote the order in which vv is added to AA, namely the size of ∣A∣|A| after vv is added.

Then, for any vertex ss, an ss-to-tt cut has weight w(t)w(t).

Proof

Define a vertex vv to be activated if and only if, when vv is added to AA, the last vertex in AA, uu, was added earlier than vv, and in the graph G′′=(V′,E′/C)G'' = (V', E'/C), uu and vv are not in the same connected component.

Stoer-Wagner1
Stoer-Wagner1

As shown in the figure, the blue and yellow regions are two different connected components; the numbers in brackets indicate the order in which vertices are added to AA. Gray vertices are activated, while white vertices are not activated.

Define Av={u∣pos⁡(u)<pos⁡(v)}A_v = \{u \mid \operatorname{pos}(u) < \operatorname{pos}(v)\}, that is, the set of vertices added strictly before vv to AA. Let EvE_v be the edge set of the subgraph of E′E' induced by the vertex set Av∪{v}A_v \cup\{v\}. (Note that it includes vertex vv.)

Define the induced cut CvC_v as C∩EvC \cap E_v. w(Cv)=∑(i,j)∈Cvd(i,j)w(C_v) = \sum_{(i,j) \in C_v} d(i, j).

Lemma 1

For any activated vertex vv, w(Av,v)≤w(Cv)w(A_v, v) \le w(C_v).

Proof: use mathematical induction.

For the first activated vertex v0v_0, by definition, w(Av0,v0)=w(Cv0)w(A_{v_0}, v_0) = w(C_{v_0}).

For two subsequent activated vertices u,vu, v, assume pos⁡(v)<pos⁡(u)\operatorname{pos}(v) < \operatorname{pos}(u). Then:

w(Au,u)=w(Av,u)+w(Au−Av,u)w(A_u, u) = w(A_v, u) + w(A_u - A_v, u)

We also know that:

w(Av,u)≤w(Av,v)w(A_v, u) \le w(A_v, v) and w(Av,v)≤w(Cv)w(A_v, v) \le w(C_v), so:

w(Au,u)≤w(Cv)+w(Au−Av,u)w(A_u, u) \le w(C_v) + w(A_u - A_v, u)

Since w(Au−Av,u)w(A_u - A_v, u) contributes to w(Cu)w(C_u) but not to w(Cv)w(C_v), and all edges have positive weights, we obtain:

w(Au,u)≤w(Cu)w(A_u,u) \le w(C_u)

This proves the claim by induction.

Since pos⁡(s)<pos⁡(t)\operatorname{pos}(s) < \operatorname{pos}(t) and s,ts, t are not in the same connected component, tt is activated. Therefore, w(At,t)≤w(Ct)=w(C)w(A_t, t) \le w(C_t) = w(C).

P5632 [Template] Stoer–Wagner Algorithm
#include <cstring>
#include <iostream>
using namespace std;
constexpr int N = 601;
int fa[N], siz[N], edge[N][N];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

int dist[N], vis[N], bin[N];
int n, m;

int contract(int &s, int &t) {  // Find s,t
  memset(dist, 0, sizeof(dist));
  memset(vis, false, sizeof(vis));
  int i, j, k, mincut, maxc;
  for (i = 1; i <= n; i++) {
    k = -1;
    maxc = -1;
    for (j = 1; j <= n; j++)
      if (!bin[j] && !vis[j] && dist[j] > maxc) {
        k = j;
        maxc = dist[j];
      }
    if (k == -1) return mincut;
    s = t;
    t = k;
    mincut = maxc;
    vis[k] = true;
    for (j = 1; j <= n; j++)
      if (!bin[j] && !vis[j]) dist[j] += edge[k][j];
  }
  return mincut;
}

constexpr int inf = 0x3f3f3f3f;

int Stoer_Wagner() {
  int mincut, i, j, s, t, ans;
  for (mincut = inf, i = 1; i < n; i++) {
    ans = contract(s, t);
    bin[t] = true;
    if (mincut > ans) mincut = ans;
    if (mincut == 0) return 0;
    for (j = 1; j <= n; j++)
      if (!bin[j]) edge[s][j] = (edge[j][s] += edge[j][t]);
  }
  return mincut;
}

int main() {
  ios::sync_with_stdio(false), cin.tie(nullptr);
  cin >> n >> m;
  if (m < n - 1) {
    cout << 0;
    return 0;
  }
  for (int i = 1; i <= n; ++i) fa[i] = i, siz[i] = 1;
  for (int i = 1, u, v, w; i <= m; ++i) {
    cin >> u >> v >> w;
    int fu = find(u), fv = find(v);
    if (fu != fv) {
      if (siz[fu] > siz[fv]) swap(fu, fv);
      fa[fu] = fv, siz[fv] += siz[fu];
    }
    edge[u][v] += w, edge[v][u] += w;
  }
  int fr = find(1);
  if (siz[fr] != n) {
    cout << 0;
    return 0;
  }
  cout << Stoer_Wagner();
  return 0;
}

Complexity Analysis and Optimization

The complexity of the contract operation is O(∣E∣+∣V∣log⁡∣V∣)O(|E| + |V|\log|V|).

There are O(∣V∣)O(|V|) contract operations in total, so the overall complexity is O(∣E∣∣V∣+∣V∣2log⁡∣V∣)O(|E||V| + |V|^2\log|V|).

As with shortest paths, the bottleneck of the algorithm is finding the vertex with the maximum weight.

One contract operation requires finding the heap maximum ∣V∣|V| times and incrementally updating edge weights ∣E∣|E| times.

A Fibonacci heap can perform heap-maximum queries in O(log⁡∣V∣)O(\log|V|) time and incremental weight updates in O(1)O(1) time, giving a theoretical complexity of O(∣E∣+∣V∣log⁡∣V∣)O(|E| + |V|\log|V|). However, Fibonacci heaps have large constants and require a lot of code, so their practical value is low.

(In actual tests, even enabling O2 requires the judge's performance fluctuations to be favorable in order to pass.)

This content comes from OI Wiki: Stoer–Wagner Algorithm. 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.