Skip to content

Commit bb6385e

Browse files
authored
feat: Add Stoer-Wagner Algorithm for Minimum Cut (#6752)
* feat: Add Stoer-Wagner Algorithm for Minimum Cut * fix: Correct Stoer-Wagner implementation * fix: Remove unused import * fix: Apply clang-format
1 parent 68746f8 commit bb6385e

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.thealgorithms.graph;
2+
3+
/**
4+
* An implementation of the Stoer-Wagner algorithm to find the global minimum cut of an undirected, weighted graph.
5+
* A minimum cut is a partition of the graph's vertices into two disjoint sets with the minimum possible edge weight
6+
* sum connecting the two sets.
7+
*
8+
* Wikipedia: https://en.wikipedia.org/wiki/Stoer%E2%80%93Wagner_algorithm
9+
* Time Complexity: O(V^3) where V is the number of vertices.
10+
*/
11+
public class StoerWagner {
12+
13+
/**
14+
* Finds the minimum cut in the given undirected, weighted graph.
15+
*
16+
* @param graph An adjacency matrix representing the graph. graph[i][j] is the weight of the edge between i and j.
17+
* @return The weight of the minimum cut.
18+
*/
19+
public int findMinCut(int[][] graph) {
20+
int n = graph.length;
21+
if (n < 2) {
22+
return 0;
23+
}
24+
25+
int[][] currentGraph = new int[n][n];
26+
for (int i = 0; i < n; i++) {
27+
System.arraycopy(graph[i], 0, currentGraph[i], 0, n);
28+
}
29+
30+
int minCut = Integer.MAX_VALUE;
31+
boolean[] merged = new boolean[n];
32+
33+
for (int phase = 0; phase < n - 1; phase++) {
34+
boolean[] inSetA = new boolean[n];
35+
int[] weights = new int[n];
36+
int prev = -1;
37+
int last = -1;
38+
39+
for (int i = 0; i < n - phase; i++) {
40+
int maxWeight = -1;
41+
int currentVertex = -1;
42+
43+
for (int j = 0; j < n; j++) {
44+
if (!merged[j] && !inSetA[j] && weights[j] > maxWeight) {
45+
maxWeight = weights[j];
46+
currentVertex = j;
47+
}
48+
}
49+
50+
if (currentVertex == -1) {
51+
// This can happen if the graph is disconnected.
52+
return 0;
53+
}
54+
55+
prev = last;
56+
last = currentVertex;
57+
inSetA[last] = true;
58+
59+
for (int j = 0; j < n; j++) {
60+
if (!merged[j] && !inSetA[j]) {
61+
weights[j] += currentGraph[last][j];
62+
}
63+
}
64+
}
65+
66+
minCut = Math.min(minCut, weights[last]);
67+
68+
// Merge 'last' vertex into 'prev' vertex
69+
for (int i = 0; i < n; i++) {
70+
currentGraph[prev][i] += currentGraph[last][i];
71+
currentGraph[i][prev] = currentGraph[prev][i];
72+
}
73+
merged[last] = true;
74+
}
75+
76+
return minCut;
77+
}
78+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.thealgorithms.graph;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
/**
8+
* Unit tests for the StoerWagner global minimum cut algorithm.
9+
*
10+
* These tests verify correctness of the implementation across
11+
* several graph configurations: simple, complete, disconnected,
12+
* and small edge cases.
13+
*/
14+
public class StoerWagnerTest {
15+
16+
@Test
17+
public void testSimpleGraph() {
18+
int[][] graph = {{0, 3, 2, 0}, {3, 0, 1, 4}, {2, 1, 0, 5}, {0, 4, 5, 0}};
19+
StoerWagner algo = new StoerWagner();
20+
assertEquals(5, algo.findMinCut(graph)); // Correct minimum cut = 5
21+
}
22+
23+
@Test
24+
public void testTriangleGraph() {
25+
int[][] graph = {{0, 2, 3}, {2, 0, 4}, {3, 4, 0}};
26+
StoerWagner algo = new StoerWagner();
27+
assertEquals(5, algo.findMinCut(graph)); // min cut = 5
28+
}
29+
30+
@Test
31+
public void testDisconnectedGraph() {
32+
int[][] graph = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
33+
StoerWagner algo = new StoerWagner();
34+
assertEquals(0, algo.findMinCut(graph)); // Disconnected graph => cut = 0
35+
}
36+
37+
@Test
38+
public void testCompleteGraph() {
39+
int[][] graph = {{0, 1, 1, 1}, {1, 0, 1, 1}, {1, 1, 0, 1}, {1, 1, 1, 0}};
40+
StoerWagner algo = new StoerWagner();
41+
assertEquals(3, algo.findMinCut(graph)); // Each vertex connected to all others
42+
}
43+
44+
@Test
45+
public void testSingleVertex() {
46+
int[][] graph = {{0}};
47+
StoerWagner algo = new StoerWagner();
48+
assertEquals(0, algo.findMinCut(graph)); // Only one vertex
49+
}
50+
51+
@Test
52+
public void testTwoVertices() {
53+
int[][] graph = {{0, 7}, {7, 0}};
54+
StoerWagner algo = new StoerWagner();
55+
assertEquals(7, algo.findMinCut(graph)); // Only one edge, cut weight = 7
56+
}
57+
58+
@Test
59+
public void testSquareGraphWithDiagonal() {
60+
int[][] graph = {{0, 2, 0, 2}, {2, 0, 3, 0}, {0, 3, 0, 4}, {2, 0, 4, 0}};
61+
StoerWagner algo = new StoerWagner();
62+
assertEquals(4, algo.findMinCut(graph)); // verified manually
63+
}
64+
}

0 commit comments

Comments
 (0)