From 66f66500eedf893a108a3f94fd19569f5fbbad2b Mon Sep 17 00:00:00 2001 From: hunter129143 <2440617071@qq.com> Date: Sat, 7 Oct 2023 23:29:22 +0800 Subject: [PATCH] Add New graphtheory Algorithm - Hungarian algorithm in Java --- .../graphtheory/HungarianAlgorithm.java | 80 +++++++++++++++++++ .../graphtheory/HungarianAlgorithmTest.java | 49 ++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/main/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithm.java create mode 100644 src/test/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithmTest.java diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithm.java b/src/main/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithm.java new file mode 100644 index 000000000..1b50fd22c --- /dev/null +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithm.java @@ -0,0 +1,80 @@ +package com.williamfiset.algorithms.graphtheory; + +import java.util.Arrays; + +public class HungarianAlgorithm { + private double[][] weightMatrix; + private int numRows; + private int numCols; + private int[] rowMatches; + private int[] colMatches; + private boolean[] rowVisited; + + public int[] findMaxWeightMatching(double[][] matrix) { + weightMatrix = matrix; + numRows = matrix.length; + numCols = matrix[0].length; + int maxDim = Math.max(numRows, numCols); + rowMatches = new int[maxDim]; + colMatches = new int[maxDim]; + rowVisited = new boolean[maxDim]; + + // Initialize matching array + Arrays.fill(rowMatches, -1); + Arrays.fill(colMatches, -1); + + // Add virtual vertices to equalize the number of personnel and tasks + if (numRows > numCols) { + weightMatrix = expandMatrix(matrix, numRows, numRows); + numCols = numRows; + } else if (numCols > numRows) { + weightMatrix = expandMatrix(matrix, numCols, numCols); + numRows = numCols; + } + + // Find the match with the maximum weight for each row + for (int row = 0; row < numRows; row++) { + Arrays.fill(rowVisited, false); + if (findAugmentingPath(row)) { + Arrays.fill(rowVisited, false); // Reset access status + } + } + + return Arrays.copyOf(rowMatches, numRows); + } + + private boolean findAugmentingPath(int row) { + if (!rowVisited[row]) { + rowVisited[row] = true; + for (int col = 0; col < numCols; col++) { + if (isMatchValid(row, col)) { + // The current match is valid + if (colMatches[col] == -1 || findAugmentingPath(colMatches[col])) { + // Augmentation path found, update matching + rowMatches[row] = col; + colMatches[col] = row; + return true; + } + } + } + } + return false; + } + + private boolean isMatchValid(int row, int col) { + // Check if there are edges in the weight matrix, or modify other conditions as needed + return weightMatrix[row][col] > 0; + } + + public static double[][] expandMatrix(double[][] matrix, int targetRows, int targetCols) { + double[][] expandedMatrix = new double[targetRows][targetCols]; + for (int row = 0; row < targetRows; row++) { + if (row < matrix.length) { + System.arraycopy(matrix[row], 0, expandedMatrix[row], 0, matrix[row].length); + } else { + Arrays.fill(expandedMatrix[row], 0.0); + } + } + return expandedMatrix; + } +} diff --git a/src/test/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithmTest.java b/src/test/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithmTest.java new file mode 100644 index 000000000..398c6c11d --- /dev/null +++ b/src/test/java/com/williamfiset/algorithms/graphtheory/HungarianAlgorithmTest.java @@ -0,0 +1,49 @@ +package com.williamfiset.algorithms.graphtheory; + +import static com.google.common.truth.Truth.assertThat; + +import java.util.*; +import org.junit.jupiter.api.*; + +class HungarianAlgorithmTest { + + @Test + void findMaxWeightMatching() { + HungarianAlgorithm hungarianAlgorithm = new HungarianAlgorithm(); + + double[][] matrix = { + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9} + }; + + int[] matching = hungarianAlgorithm.findMaxWeightMatching(matrix); + + int[] expectedMatching = {2, 1, 0}; + + assertThat(matching).isEqualTo(expectedMatching); + } + + @Test + void expandMatrix() { + HungarianAlgorithm hungarianAlgorithm = new HungarianAlgorithm(); + + double[][] matrix = { + {1, 2}, + {3, 4} + }; + + int targetRows = 3; + int targetCols = 3; + + double[][] expandedMatrix = hungarianAlgorithm.expandMatrix(matrix, targetRows, targetCols); + + double[][] expectedMatrix = { + {1, 2, 0}, + {3, 4, 0}, + {0, 0, 0} + }; + + assertThat(expandedMatrix).isEqualTo(expectedMatrix); + } +}