package association; /* * Created on Apr 25, 2005 * * Munkres-Kuhn (Hungarian) Algorithm Clean Version: 0.11 * * Konstantinos A. Nedas * Department of Spatial Information Science & Engineering * University of Maine, Orono, ME 04469-5711, USA * kostas@spatial.maine.edu * http://www.spatial.maine.edu/~kostas * * This Java class implements the Hungarian algorithm [a.k.a Munkres' algorithm, * a.k.a. Kuhn algorithm, a.k.a. Assignment problem, a.k.a. Marriage problem, * a.k.a. Maximum Weighted Maximum Cardinality Bipartite Matching]. * * [It can be used as a method call from within any main (or other function).] * It takes 2 arguments: * a. A 2-D array (could be rectangular or square). * b. A string ("min" or "max") specifying whether you want the min or max assignment. * [It returns an assignment matrix[array.length][2] that contains the row and col of * the elements (in the original inputted array) that make up the optimum assignment.] * * [This version contains only scarce comments. If you want to understand the * inner workings of the algorithm, get the tutorial version of the algorithm * from the same website you got this one (http://www.spatial.maine.edu/~kostas/dev/soft/munkres.htm)] * * Any comments, corrections, or additions would be much appreciated. * Credit due to professor Bob Pilgrim for providing an online copy of the * pseudocode for this algorithm (http://216.249.163.93/bob.pilgrim/445/munkres.html) * * Feel free to redistribute this source code, as long as this header--with * the exception of sections in brackets--remains as part of the file. * * Requirements: JDK 1.5.0_01 or better. * [Created in Eclipse 3.1M6 (www.eclipse.org).] * */ import java.lang.System; public class HungarianAlgorithm { //*******************************************// //METHODS THAT PERFORM ARRAY-PROCESSING TASKS// //*******************************************// //Finds the largest element in a positive array. public double findLargest (double[][] array) { //works for arrays where all values are >= 0. double largest = 0; for (int i=0; i largest) largest = array[i][j]; } } return largest; } //Transposes a double[][] array. public double[][] transpose (double[][] array) { double[][] transposedArray = new double[array[0].length][array.length]; for (int i=0; icost[i][j]) minval=cost[i][j]; } for (int j=0; j=mask.length) //Should be cost.length but ok, because mask has same dimensions. step=7; else step=4; return step; } public int hg_step4 (int step, double[][] cost, int[][] mask, int[] rowCover, int[] colCover, int[] zero_RC) { //What STEP 4 does: //Find an uncovered zero in cost and prime it (if none go to step 6). Check for star in same row: //if yes, cover the row and uncover the star's column. Repeat until no uncovered zeros are left //and go to step 6. If not, save location of primed zero and go to step 5. int[] row_col = new int[2]; //Holds row and col of uncovered zero. boolean done = false; while (done == false) { row_col = findUncoveredZero(row_col, cost, rowCover, colCover); if (row_col[0] == -1) { done = true; step = 6; } else { mask[row_col[0]][row_col[1]] = 2; //Prime the found uncovered zero. boolean starInRow = false; for (int j=0; j= cost.length) done = true; }//end outer while return row_col; } public int hg_step5 (int step, int[][] mask, int[] rowCover, int[] colCover, int[] zero_RC) { //What STEP 5 does: //Construct series of alternating primes and stars. Start with prime from step 4. //Take star in the same column. Next take prime in the same row as the star. Finish //at a prime with no star in its column. Unstar all stars and star the primes of the //series. Erasy any other primes. Reset covers. Go to step 3. int count = 0; //Counts rows of the path matrix. int[][] path = new int[(mask[0].length*mask.length)][2]; //Path matrix (stores row and col). path[count][0] = zero_RC[0]; //Row of last prime. path[count][1] = zero_RC[1]; //Column of last prime. boolean done = false; while (done == false) { int r = findStarInCol(mask, path[count][1]); if (r>=0) { count = count+1; path[count][0] = r; //Row of starred zero. path[count][1] = path[count-1][1]; //Column of starred zero. } else done = true; if (done == false) { int c = findPrimeInRow(mask, path[count][0]); count = count+1; path[count][0] = path [count-1][0]; //Row of primed zero. path[count][1] = c; //Col of primed zero. } }//end while convertPath(mask, path, count); clearCovers(rowCover, colCover); erasePrimes(mask); step = 3; return step; } //Aux 1 for hg_step5. public int findStarInCol (int[][] mask, int col) { int r=-1; //Again this is a check value. for (int i=0; i cost[i][j])) minval = cost[i][j]; } } return minval; } public void main (String[] args) { //Below enter "max" or "min" to find maximum sum or minimum sum assignment. String sumType = "max"; //int numOfRows = 4; //readInput("How many rows for the matrix? "); //int numOfCols = 4; //readInput("How many columns for the matrix? "); //double[][] array = {{0,0,0,0},{0,0,0,-1},{0,0,-1,-1}, {0,-1,-1,-1}};//new double[numOfRows][numOfCols]; double[][] array = {{0,-1,-1,0},{0,-1,0,-1},{0,0,-1,-1}}; if (array.length > array[0].length) { System.out.println("Array transposed (because rows>columns).\n"); //Cols must be >= Rows. array = transpose(array); } System.out.println("The matrix is:"); for (int i = 0; i < array.length; i++) { System.out.print("|\t"); for (int j = 0; j < array[i].length; j++) System.out.print(array[i][j]+"\t"); System.out.println("|"); } System.out.println(); int[][] assignment = new int[array.length][2]; assignment = hgAlgorithm(array, sumType); //Call Hungarian algorithm. System.out.println("The winning assignment (" + sumType + " sum) is:\n"); double sum = 0; for (int i=0; i