Skip to content

Commit 7e86329

Browse files
committed
fix: Correct Stoer-Wagner implementation
1 parent 9e1105a commit 7e86329

File tree

2 files changed

+42
-95
lines changed

2 files changed

+42
-95
lines changed
Lines changed: 35 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.thealgorithms.graph;
22

3+
import java.util.Arrays;
4+
35
/**
46
* An implementation of the Stoer-Wagner algorithm to find the global minimum cut of an undirected, weighted graph.
57
* A minimum cut is a partition of the graph's vertices into two disjoint sets with the minimum possible edge weight
@@ -22,85 +24,57 @@ public int findMinCut(int[][] graph) {
2224
return 0;
2325
}
2426

25-
// Make a working copy of the adjacency matrix so we can merge vertices
26-
int[][] g = new int[n][n];
27+
int[][] currentGraph = new int[n][n];
2728
for (int i = 0; i < n; i++) {
28-
System.arraycopy(graph[i], 0, g[i], 0, n);
29+
System.arraycopy(graph[i], 0, currentGraph[i], 0, n);
2930
}
3031

31-
// vertices contains the list of active vertex indices (initially 0..n-1)
32-
int[] vertices = new int[n];
33-
for (int i = 0; i < n; i++) {
34-
vertices[i] = i;
35-
}
32+
int minCut = Integer.MAX_VALUE;
33+
boolean[] merged = new boolean[n];
3634

37-
int bestCut = Integer.MAX_VALUE;
35+
for (int phase = 0; phase < n - 1; phase++) {
36+
boolean[] inSetA = new boolean[n];
37+
int[] weights = new int[n];
38+
int prev = -1;
39+
int last = -1;
3840

39-
// Repeat n-1 phases; in each phase we reduce number of active vertices by 1
40-
for (int m = n; m > 1; m--) {
41-
int[] weights = new int[n]; // accumulated weights for selection
42-
boolean[] added = new boolean[n]; // which original vertices have been added in this phase
43-
int prev = -1; // previously added vertex id in the growing set
41+
for (int i = 0; i < n - phase; i++) {
42+
int maxWeight = -1;
43+
int currentVertex = -1;
4444

45-
for (int i = 0; i < m; i++) {
46-
// Select the not-yet-added vertex (among the first m active vertices) with maximum weight
47-
int sel = -1;
48-
for (int j = 0; j < m; j++) {
49-
int v = vertices[j];
50-
if (!added[v] && (sel == -1 || weights[v] > weights[sel])) {
51-
sel = v;
45+
for (int j = 0; j < n; j++) {
46+
if (!merged[j] && !inSetA[j] && weights[j] > maxWeight) {
47+
maxWeight = weights[j];
48+
currentVertex = j;
5249
}
5350
}
5451

55-
// If sel is -1 it means the graph is disconnected in the remaining part;
56-
// the minimum cut value is 0 in that case.
57-
if (sel == -1) {
52+
if (currentVertex == -1) {
53+
// This can happen if the graph is disconnected.
5854
return 0;
5955
}
6056

61-
added[sel] = true;
57+
prev = last;
58+
last = currentVertex;
59+
inSetA[last] = true;
6260

63-
// If this is the last vertex added in this phase, weights[sel] is the cut weight between sel and the rest.
64-
if (i == m - 1) {
65-
// Update best cut
66-
if (weights[sel] < bestCut) {
67-
bestCut = weights[sel];
61+
for (int j = 0; j < n; j++) {
62+
if (!merged[j] && !inSetA[j]) {
63+
weights[j] += currentGraph[last][j];
6864
}
65+
}
66+
}
6967

70-
// Merge 'sel' into 'prev' (combine their edges) to reduce vertex count
71-
if (prev != -1) {
72-
for (int k = 0; k < n; k++) {
73-
// accumulate edges from sel into prev
74-
g[prev][k] += g[sel][k];
75-
g[k][prev] = g[prev][k];
76-
}
68+
minCut = Math.min(minCut, weights[last]);
7769

78-
// Remove 'sel' from vertices[] by replacing it with last active vertex
79-
int selIndex = -1;
80-
for (int j = 0; j < m; j++) {
81-
if (vertices[j] == sel) {
82-
selIndex = j;
83-
break;
84-
}
85-
}
86-
// replace position selIndex with last active vertex (m-1)
87-
vertices[selIndex] = vertices[m - 1];
88-
}
89-
// Phase done
90-
} else {
91-
// not last: update weights of remaining active vertices
92-
for (int j = 0; j < m; j++) {
93-
int v = vertices[j];
94-
if (!added[v]) {
95-
weights[v] += g[sel][v];
96-
}
97-
}
98-
prev = sel;
99-
}
70+
// Merge 'last' vertex into 'prev' vertex
71+
for (int i = 0; i < n; i++) {
72+
currentGraph[prev][i] += currentGraph[last][i];
73+
currentGraph[i][prev] = currentGraph[prev][i];
10074
}
75+
merged[last] = true;
10176
}
10277

103-
return bestCut == Integer.MAX_VALUE ? 0 : bestCut;
78+
return minCut;
10479
}
10580
}
106-

src/test/java/com/thealgorithms/graph/StoerWagnerTest.java

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
/**
88
* Unit tests for the StoerWagner global minimum cut algorithm.
9-
*
9+
*
1010
* These tests verify correctness of the implementation across
1111
* several graph configurations: simple, complete, disconnected,
1212
* and small edge cases.
@@ -15,46 +15,28 @@ public class StoerWagnerTest {
1515

1616
@Test
1717
public void testSimpleGraph() {
18-
int[][] graph = {
19-
{0, 3, 2, 0},
20-
{3, 0, 1, 4},
21-
{2, 1, 0, 5},
22-
{0, 4, 5, 0}
23-
};
18+
int[][] graph = {{0, 3, 2, 0}, {3, 0, 1, 4}, {2, 1, 0, 5}, {0, 4, 5, 0}};
2419
StoerWagner algo = new StoerWagner();
2520
assertEquals(5, algo.findMinCut(graph)); // Correct minimum cut = 5
2621
}
2722

2823
@Test
2924
public void testTriangleGraph() {
30-
int[][] graph = {
31-
{0, 2, 3},
32-
{2, 0, 4},
33-
{3, 4, 0}
34-
};
25+
int[][] graph = {{0, 2, 3}, {2, 0, 4}, {3, 4, 0}};
3526
StoerWagner algo = new StoerWagner();
3627
assertEquals(5, algo.findMinCut(graph)); // min cut = 5
3728
}
3829

3930
@Test
4031
public void testDisconnectedGraph() {
41-
int[][] graph = {
42-
{0, 0, 0},
43-
{0, 0, 0},
44-
{0, 0, 0}
45-
};
32+
int[][] graph = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
4633
StoerWagner algo = new StoerWagner();
4734
assertEquals(0, algo.findMinCut(graph)); // Disconnected graph => cut = 0
4835
}
4936

5037
@Test
5138
public void testCompleteGraph() {
52-
int[][] graph = {
53-
{0, 1, 1, 1},
54-
{1, 0, 1, 1},
55-
{1, 1, 0, 1},
56-
{1, 1, 1, 0}
57-
};
39+
int[][] graph = {{0, 1, 1, 1}, {1, 0, 1, 1}, {1, 1, 0, 1}, {1, 1, 1, 0}};
5840
StoerWagner algo = new StoerWagner();
5941
assertEquals(3, algo.findMinCut(graph)); // Each vertex connected to all others
6042
}
@@ -68,24 +50,15 @@ public void testSingleVertex() {
6850

6951
@Test
7052
public void testTwoVertices() {
71-
int[][] graph = {
72-
{0, 7},
73-
{7, 0}
74-
};
53+
int[][] graph = {{0, 7}, {7, 0}};
7554
StoerWagner algo = new StoerWagner();
7655
assertEquals(7, algo.findMinCut(graph)); // Only one edge, cut weight = 7
7756
}
7857

7958
@Test
8059
public void testSquareGraphWithDiagonal() {
81-
int[][] graph = {
82-
{0, 2, 0, 2},
83-
{2, 0, 3, 0},
84-
{0, 3, 0, 4},
85-
{2, 0, 4, 0}
86-
};
60+
int[][] graph = {{0, 2, 0, 2}, {2, 0, 3, 0}, {0, 3, 0, 4}, {2, 0, 4, 0}};
8761
StoerWagner algo = new StoerWagner();
8862
assertEquals(4, algo.findMinCut(graph)); // verified manually
8963
}
9064
}
91-

0 commit comments

Comments
 (0)