Stoer–Wagner algorithm

(Redirected from Stoer-Wagner algorithm)

In graph theory, the Stoer–Wagner algorithm is a recursive algorithm to solve the minimum cut problem in undirected weighted graphs with non-negative weights. It was proposed by Mechthild Stoer and Frank Wagner in 1995. The essential idea of this algorithm is to shrink the graph by merging the most intensive vertices, until the graph only contains two combined vertex sets.[2] At each phase, the algorithm finds the minimum - cut for two vertices and chosen at its will. Then the algorithm shrinks the edge between and to search for non - cuts. The minimum cut found in all phases will be the minimum weighted cut of the graph.

A min-cut of a weighted graph having min-cut weight 4[1]

A cut is a partition of the vertices of a graph into two non-empty, disjoint subsets. A minimum cut is a cut for which the size or weight of the cut is not larger than the size of any other cut. For an unweighted graph, the minimum cut would simply be the cut with the least edges. For a weighted graph, the sum of all edges' weight on the cut determines whether it is a minimum cut. In practice, the minimum cut problem is always discussed with the maximum flow problem, to explore the maximum capacity of a network, since the minimum cut is a bottleneck in a graph or network.

Stoer–Wagner minimum cut algorithm edit

Let   be a weighted undirected graph. Suppose that  . The cut is called an  -  cut if exactly one of   or   is in  . The minimal cut of   that is also an  -  cut is called the  -  min-cut of  .[3]

This algorithm starts by finding an   and a   in  , and an s-t min-cut   of  . For any pair  , there are two possible situations: either   is a global min-cut of  , or   and   belong to the same side of the global min-cut of  . Therefore, the global min-cut can be found by checking the graph  , which is the graph after merging vertices   and   into a new vertex  . During the merging, if   and   are connected by an edge then this edge disappears. If   and   both have edges to some vertex  , then the weight of the edge from the new vertex   to   is  .[3] The algorithm is described as:[2]

MinimumCutPhase 
     
    while  
        add to   the most tightly connected vertex
    end
    store the cut in which the last remaining vertex is by itself (the "cut-of-the-phase") 
    shrink   by merging the two vertices (s, t) added last (the value of "cut-of-the-phase" is the value of minimum s, t cut.)

MinimumCut 
    while  
        MinimumCutPhase 
        if the cut-of-the-phase is lighter than the current minimum cut
            then store the cut-of-the-phase as the current minimum cut

The algorithm works in phases. In the MinimumCutPhase, the subset   of the graphs vertices grows starting with an arbitrary single vertex until   is equal to  . In each step, the vertex which is outside of  , but most tightly connected with   is added to the set  . This procedure can be formally shown as:[2] add vertex   such that  , where   is the sum of the weights of all the edges between   and  . So, in a single phase, a pair of vertices   and   , and a min   cut   is determined.[4] After one phase of the MinimumCutPhase, the two vertices are merged as a new vertex, and edges from the two vertices to a remaining vertex are replaced by an edge weighted by the sum of the weights of the previous two edges. Edges joining the merged nodes are removed. If there is a minimum cut of   separating   and  , the   is a minimum cut of  . If not, then the minimum cut of   must have   and   on a same side. Therefore, the algorithm would merge them as one node. In addition, the MinimumCut would record and update the global minimum cut after each MinimumCutPhase. After   phases, the minimum cut can be determined.[4]

Example edit

This section refers to Figs. 1–6 in the original paper.[2]

The graph in step 1 shows the original graph   and randomly selects node 2 as the starting node for this algorithm. In the MinimumCutPhase, set   only has node 2, the heaviest edge is edge (2,3), so node 3 is added into set  . Next, set   contains node 2 and node 3, the heaviest edge is (3,4), thus node 4 is added to set  . By following this procedure, the last two nodes are node 5 and node 1, which are   and   in this phase. By merging them into node 1+5, the new graph is as shown in step 2. In this phase, the weight of cut is 5, which is the summation of edges (1,2) and (1,5). Right now, the first loop of MinimumCut is completed.

In step 2, starting from node 2, the heaviest edge is (2,1+5), thus node 1+5 is put in set  . The next heaviest edges is (2,3) or (1+5,6), we choose (1+5,6) thus node 6 is added to the set. Then we compare edge (2,3) and (6,7) and choose node 3 to put in set  . The last two nodes are node 7 and node 8. Therefore, merge edge (7,8). The minimum cut is 5, so remain the minimum as 5.

The following steps repeat the same operations on the merged graph, until there is only one edge in the graph, as shown in step 7. The global minimum cut has edge (2,3) and edge (6,7), which is detected in step 5.

Proof of correctness edit

To prove the correctness of this algorithm, we need to prove that the cut given by MinimumCutPhase is in fact a minimum   cut of the graph, where s and t are the two vertices last added in the phase. Therefore, a lemma is shown below:

Lemma 1: MinimumCutPhase returns a minimum  -cut of  .

Let   be an arbitrary   cut, and   be the cut given by the phase. We must show that  . Observe that a single run of MinimumCutPhase gives us an ordering of all the vertices in the graph (where   is the first and   and   are the two vertices added last in the phase). We say the vertex   is active if   and the vertex added just before   are in opposite sides of the cut. We prove the lemma by induction on the set of active vertices. We define   as the set of vertices added to   before  , and   to be the set of edges in   with both of their ends in  , i.e.   is the cut induced by  . We prove, for each active vertex  ,

 

Let   be the first active vertex. By the definition of these two quantities,   and   are equivalent.   is simply all vertices added to   before  , and the edges between these vertices and   are the edges that cross the cut  . Therefore, as shown above, for active vertices   and  , with   added to   before  :

 

  by induction,  

  since   contributes to   but not to   (and other edges are of non-negative weights)

Thus, since   is always an active vertex since the last cut of the phase separates   from   by definition, for any active vertex  :

 

Therefore, the cut of the phase is at most as heavy as  .

Time complexity edit

The running time of the algorithm MinimumCut is equal to the added running time of the   runs of MinimumCutPhase, which is called on graphs with decreasing number of vertices and edges.

For the MinimumCutPhase, a single run of it needs at most   time.

Therefore, the overall running time should be the product of two phase complexity, which is  .[2]

For the further improvement, the key is to make it easy to select the next vertex to be added to the set  , the most tightly connected vertex. During execution of a phase, all vertices that are not in   reside in a priority queue based on a key field. The key of a vertex   is the sum of the weights of the edges connecting it to the current  , that is,  . Whenever a vertex   is added to   we have to perform an update of the queue.   has to be deleted from the queue, and the key of every vertex   not in  , connected to   has to be increased by the weight of the edge  , if it exists. As this is done exactly once for every edge, overall we have to perform   ExtractMax and   IncreaseKey operations. By using the Fibonacci heap we can perform an ExtractMax operation in   amortized time and an IncreaseKey operation in   amortized time. Thus, the time we need for this key step that dominates the rest of the phase, is  .[2]

Example code edit

Below is a concise C++ implementation of the Stoer–Wagner algorithm.[5]

// Adjacency matrix implementation of Stoer–Wagner min cut algorithm.
//
// Running time:
//     O(|V|^3)

#include <bits/stdc++.h>
using namespace std;

pair<int, vector<int>> globalMinCut(vector<vector<int>> mat) {
    pair<int, vector<int>> best = {INT_MAX, {}};
    int n = mat.size();
    vector<vector<int>> co(n);

    for (int i = 0; i < n; i++)
        co[i] = {i};

    for (int ph = 1; ph < n; ph++) {
        vector<int> w = mat[0];
        size_t s = 0, t = 0;
        for (int it = 0; it < n - ph; it++) { // O(V^2) -> O(E log V) with prio. queue
            w[t] = INT_MIN;
            s = t, t = max_element(w.begin(), w.end()) - w.begin();
            for (int i = 0; i < n; i++) w[i] += mat[t][i];
        }
        best = min(best, {w[t] - mat[t][t], co[t]});
        co[s].insert(co[s].end(), co[t].begin(), co[t].end());
        for (int i = 0; i < n; i++) mat[s][i] += mat[t][i];
        for (int i = 0; i < n; i++) mat[i][s] = mat[s][i];
        mat[0][t] = INT_MIN;
    }

    return best;
}

[citation needed]

const int maxn = 550;
const int inf = 1000000000;
int n, r;
int edge[maxn][maxn], dist[maxn];
bool vis[maxn], bin[maxn];

void init()
{
    memset(edge, 0, sizeof(edge));
    memset(bin, false, sizeof(bin));
}

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;  
}

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;
}

References edit

  1. ^ "Boost Graph Library: Stoer–Wagner Min-Cut - 1.46.1". www.boost.org. Retrieved 2015-12-07.
  2. ^ a b c d e f "A Simple Min-Cut Algorithm".
  3. ^ a b "Lecture notes for Analysis of Algorithms": Global minimum cuts" (PDF).
  4. ^ a b "The minimum cut algorithm of Stoer and Wagner" (PDF).
  5. ^ "KTH Algorithm Competition Template Library". github.com. Retrieved 2021-11-17.

External links edit