| | 1 | /* |
| | 2 | * Created on Apr 25, 2005 |
| | 3 | * |
| | 4 | * Munkres-Kuhn (Hungarian) Algorithm Clean Version: 0.11 |
| | 5 | * |
| | 6 | * Konstantinos A. Nedas |
| | 7 | * Department of Spatial Information Science & Engineering |
| | 8 | * University of Maine, Orono, ME 04469-5711, USA |
| | 9 | * kostas@spatial.maine.edu |
| | 10 | * http://www.spatial.maine.edu/~kostas |
| | 11 | * |
| | 12 | * This Java class implements the Hungarian algorithm [a.k.a Munkres' algorithm, |
| | 13 | * a.k.a. Kuhn algorithm, a.k.a. Assignment problem, a.k.a. Marriage problem, |
| | 14 | * a.k.a. Maximum Weighted Maximum Cardinality Bipartite Matching]. |
| | 15 | * |
| | 16 | * [It can be used as a method call from within any main (or other function).] |
| | 17 | * It takes 2 arguments: |
| | 18 | * a. A 2-D array (could be rectangular or square). |
| | 19 | * b. A string ("min" or "max") specifying whether you want the min or max assignment. |
| | 20 | * [It returns an assignment matrix[array.length][2] that contains the row and col of |
| | 21 | * the elements (in the original inputted array) that make up the optimum assignment.] |
| | 22 | * |
| | 23 | * [This version contains only scarce comments. If you want to understand the |
| | 24 | * inner workings of the algorithm, get the tutorial version of the algorithm |
| | 25 | * from the same website you got this one (http://www.spatial.maine.edu/~kostas/dev/soft/munkres.htm)] |
| | 26 | * |
| | 27 | * Any comments, corrections, or additions would be much appreciated. |
| | 28 | * Credit due to professor Bob Pilgrim for providing an online copy of the |
| | 29 | * pseudocode for this algorithm (http://216.249.163.93/bob.pilgrim/445/munkres.html) |
| | 30 | * |
| | 31 | * Feel free to redistribute this source code, as long as this header--with |
| | 32 | * the exception of sections in brackets--remains as part of the file. |
| | 33 | * |
| | 34 | * Requirements: JDK 1.5.0_01 or better. |
| | 35 | * [Created in Eclipse 3.1M6 (www.eclipse.org).] |
| | 36 | * |
| | 37 | */ |
| | 38 | |
| | 39 | package utilsplugin2.dumbutils; |
| | 40 | |
| | 41 | import static java.lang.Math.*; |
| | 42 | import java.util.*; |
| | 43 | |
| | 44 | public class HungarianAlgorithm { |
| | 45 | |
| | 46 | //********************************// |
| | 47 | //METHODS FOR CONSOLE INPUT-OUTPUT// |
| | 48 | //********************************// |
| | 49 | |
| | 50 | public static int readInput(String prompt) //Reads input,returns double. |
| | 51 | { |
| | 52 | Scanner in = new Scanner(System.in); |
| | 53 | System.out.print(prompt); |
| | 54 | int input = in.nextInt(); |
| | 55 | return input; |
| | 56 | } |
| | 57 | public static void printTime(double time) //Formats time output. |
| | 58 | { |
| | 59 | String timeElapsed = ""; |
| | 60 | int days = (int)floor(time)/(24 * 3600); |
| | 61 | int hours = (int)floor(time%(24*3600))/(3600); |
| | 62 | int minutes = (int)floor((time%3600)/60); |
| | 63 | int seconds = (int)round(time%60); |
| | 64 | |
| | 65 | if (days > 0) |
| | 66 | timeElapsed = Integer.toString(days) + "d:"; |
| | 67 | if (hours > 0) |
| | 68 | timeElapsed = timeElapsed + Integer.toString(hours) + "h:"; |
| | 69 | if (minutes > 0) |
| | 70 | timeElapsed = timeElapsed + Integer.toString(minutes) + "m:"; |
| | 71 | |
| | 72 | timeElapsed = timeElapsed + Integer.toString(seconds) + "s"; |
| | 73 | System.out.print("\nTotal time required: " + timeElapsed + "\n\n"); |
| | 74 | } |
| | 75 | |
| | 76 | //*******************************************// |
| | 77 | //METHODS THAT PERFORM ARRAY-PROCESSING TASKS// |
| | 78 | //*******************************************// |
| | 79 | |
| | 80 | public static void generateRandomArray //Generates random 2-D array. |
| | 81 | (double[][] array, String randomMethod) |
| | 82 | { |
| | 83 | Random generator = new Random(); |
| | 84 | for (int i=0; i<array.length; i++) |
| | 85 | { |
| | 86 | for (int j=0; j<array[i].length; j++) |
| | 87 | { |
| | 88 | if (randomMethod.equals("random")) |
| | 89 | {array[i][j] = generator.nextDouble();} |
| | 90 | if (randomMethod.equals("gaussian")) |
| | 91 | { |
| | 92 | array[i][j] = generator.nextGaussian()/4; //range length to 1. |
| | 93 | if (array[i][j] > 0.5) {array[i][j] = 0.5;} //eliminate outliers. |
| | 94 | if (array[i][j] < -0.5) {array[i][j] = -0.5;} //eliminate outliers. |
| | 95 | array[i][j] = array[i][j] + 0.5; //make elements positive. |
| | 96 | } |
| | 97 | } |
| | 98 | } |
| | 99 | } |
| | 100 | public static double findLargest //Finds the largest element in a positive array. |
| | 101 | (double[][] array) |
| | 102 | //works for arrays where all values are >= 0. |
| | 103 | { |
| | 104 | double largest = 0; |
| | 105 | for (int i=0; i<array.length; i++) |
| | 106 | { |
| | 107 | for (int j=0; j<array[i].length; j++) |
| | 108 | { |
| | 109 | if (array[i][j] > largest) |
| | 110 | { |
| | 111 | largest = array[i][j]; |
| | 112 | } |
| | 113 | } |
| | 114 | } |
| | 115 | |
| | 116 | return largest; |
| | 117 | } |
| | 118 | public static double[][] transpose //Transposes a double[][] array. |
| | 119 | (double[][] array) |
| | 120 | { |
| | 121 | double[][] transposedArray = new double[array[0].length][array.length]; |
| | 122 | for (int i=0; i<transposedArray.length; i++) |
| | 123 | { |
| | 124 | for (int j=0; j<transposedArray[i].length; j++) |
| | 125 | {transposedArray[i][j] = array[j][i];} |
| | 126 | } |
| | 127 | return transposedArray; |
| | 128 | } |
| | 129 | public static double[][] copyOf //Copies all elements of an array to a new array. |
| | 130 | (double[][] original) |
| | 131 | { |
| | 132 | double[][] copy = new double[original.length][original[0].length]; |
| | 133 | for (int i=0; i<original.length; i++) |
| | 134 | { |
| | 135 | //Need to do it this way, otherwise it copies only memory location |
| | 136 | System.arraycopy(original[i], 0, copy[i], 0, original[i].length); |
| | 137 | } |
| | 138 | |
| | 139 | return copy; |
| | 140 | } |
| | 141 | |
| | 142 | //**********************************// |
| | 143 | //METHODS OF THE HUNGARIAN ALGORITHM// |
| | 144 | //**********************************// |
| | 145 | |
| | 146 | public static int[][] hgAlgorithm (double[][] array, String sumType) |
| | 147 | { |
| | 148 | double[][] cost = copyOf(array); //Create the cost matrix |
| | 149 | |
| | 150 | if (sumType.equalsIgnoreCase("max")) //Then array is weight array. Must change to cost. |
| | 151 | { |
| | 152 | double maxWeight = findLargest(cost); |
| | 153 | for (int i=0; i<cost.length; i++) //Generate cost by subtracting. |
| | 154 | { |
| | 155 | for (int j=0; j<cost[i].length; j++) |
| | 156 | { |
| | 157 | cost [i][j] = (maxWeight - cost [i][j]); |
| | 158 | } |
| | 159 | } |
| | 160 | } |
| | 161 | double maxCost = findLargest(cost); //Find largest cost matrix element (needed for step 6). |
| | 162 | |
| | 163 | int[][] mask = new int[cost.length][cost[0].length]; //The mask array. |
| | 164 | int[] rowCover = new int[cost.length]; //The row covering vector. |
| | 165 | int[] colCover = new int[cost[0].length]; //The column covering vector. |
| | 166 | int[] zero_RC = new int[2]; //Position of last zero from Step 4. |
| | 167 | int step = 1; |
| | 168 | boolean done = false; |
| | 169 | while (done == false) //main execution loop |
| | 170 | { |
| | 171 | switch (step) |
| | 172 | { |
| | 173 | case 1: |
| | 174 | step = hg_step1(step, cost); |
| | 175 | break; |
| | 176 | case 2: |
| | 177 | step = hg_step2(step, cost, mask, rowCover, colCover); |
| | 178 | break; |
| | 179 | case 3: |
| | 180 | step = hg_step3(step, mask, colCover); |
| | 181 | break; |
| | 182 | case 4: |
| | 183 | step = hg_step4(step, cost, mask, rowCover, colCover, zero_RC); |
| | 184 | break; |
| | 185 | case 5: |
| | 186 | step = hg_step5(step, mask, rowCover, colCover, zero_RC); |
| | 187 | break; |
| | 188 | case 6: |
| | 189 | step = hg_step6(step, cost, rowCover, colCover, maxCost); |
| | 190 | break; |
| | 191 | case 7: |
| | 192 | done=true; |
| | 193 | break; |
| | 194 | } |
| | 195 | }//end while |
| | 196 | |
| | 197 | int[][] assignment = new int[array.length][2]; //Create the returned array. |
| | 198 | for (int i=0; i<mask.length; i++) |
| | 199 | { |
| | 200 | for (int j=0; j<mask[i].length; j++) |
| | 201 | { |
| | 202 | if (mask[i][j] == 1) |
| | 203 | { |
| | 204 | assignment[i][0] = i; |
| | 205 | assignment[i][1] = j; |
| | 206 | } |
| | 207 | } |
| | 208 | } |
| | 209 | |
| | 210 | //If you want to return the min or max sum, in your own main method |
| | 211 | //instead of the assignment array, then use the following code: |
| | 212 | /* |
| | 213 | double sum = 0; |
| | 214 | for (int i=0; i<assignment.length; i++) |
| | 215 | { |
| | 216 | sum = sum + array[assignment[i][0]][assignment[i][1]]; |
| | 217 | } |
| | 218 | return sum; |
| | 219 | */ |
| | 220 | //Of course you must also change the header of the method to: |
| | 221 | //public static double hgAlgorithm (double[][] array, String sumType) |
| | 222 | |
| | 223 | return assignment; |
| | 224 | } |
| | 225 | public static int hg_step1(int step, double[][] cost) |
| | 226 | { |
| | 227 | //What STEP 1 does: |
| | 228 | //For each row of the cost matrix, find the smallest element |
| | 229 | //and subtract it from from every other element in its row. |
| | 230 | |
| | 231 | double minval; |
| | 232 | |
| | 233 | for (int i=0; i<cost.length; i++) |
| | 234 | { |
| | 235 | minval=cost[i][0]; |
| | 236 | for (int j=0; j<cost[i].length; j++) //1st inner loop finds min val in row. |
| | 237 | { |
| | 238 | if (minval>cost[i][j]) |
| | 239 | { |
| | 240 | minval=cost[i][j]; |
| | 241 | } |
| | 242 | } |
| | 243 | for (int j=0; j<cost[i].length; j++) //2nd inner loop subtracts it. |
| | 244 | { |
| | 245 | cost[i][j]=cost[i][j]-minval; |
| | 246 | } |
| | 247 | } |
| | 248 | |
| | 249 | step=2; |
| | 250 | return step; |
| | 251 | } |
| | 252 | public static int hg_step2(int step, double[][] cost, int[][] mask, int[]rowCover, int[] colCover) |
| | 253 | { |
| | 254 | //What STEP 2 does: |
| | 255 | //Marks uncovered zeros as starred and covers their row and column. |
| | 256 | |
| | 257 | for (int i=0; i<cost.length; i++) |
| | 258 | { |
| | 259 | for (int j=0; j<cost[i].length; j++) |
| | 260 | { |
| | 261 | if ((cost[i][j]==0) && (colCover[j]==0) && (rowCover[i]==0)) |
| | 262 | { |
| | 263 | mask[i][j]=1; |
| | 264 | colCover[j]=1; |
| | 265 | rowCover[i]=1; |
| | 266 | } |
| | 267 | } |
| | 268 | } |
| | 269 | |
| | 270 | clearCovers(rowCover, colCover); //Reset cover vectors. |
| | 271 | |
| | 272 | step=3; |
| | 273 | return step; |
| | 274 | } |
| | 275 | public static int hg_step3(int step, int[][] mask, int[] colCover) |
| | 276 | { |
| | 277 | //What STEP 3 does: |
| | 278 | //Cover columns of starred zeros. Check if all columns are covered. |
| | 279 | |
| | 280 | for (int i=0; i<mask.length; i++) //Cover columns of starred zeros. |
| | 281 | { |
| | 282 | for (int j=0; j<mask[i].length; j++) |
| | 283 | { |
| | 284 | if (mask[i][j] == 1) |
| | 285 | { |
| | 286 | colCover[j]=1; |
| | 287 | } |
| | 288 | } |
| | 289 | } |
| | 290 | |
| | 291 | int count=0; |
| | 292 | for (int j=0; j<colCover.length; j++) //Check if all columns are covered. |
| | 293 | { |
| | 294 | count=count+colCover[j]; |
| | 295 | } |
| | 296 | |
| | 297 | if (count>=mask.length) //Should be cost.length but ok, because mask has same dimensions. |
| | 298 | { |
| | 299 | step=7; |
| | 300 | } |
| | 301 | else |
| | 302 | { |
| | 303 | step=4; |
| | 304 | } |
| | 305 | |
| | 306 | return step; |
| | 307 | } |
| | 308 | public static int hg_step4(int step, double[][] cost, int[][] mask, int[] rowCover, int[] colCover, int[] zero_RC) |
| | 309 | { |
| | 310 | //What STEP 4 does: |
| | 311 | //Find an uncovered zero in cost and prime it (if none go to step 6). Check for star in same row: |
| | 312 | //if yes, cover the row and uncover the star's column. Repeat until no uncovered zeros are left |
| | 313 | //and go to step 6. If not, save location of primed zero and go to step 5. |
| | 314 | |
| | 315 | int[] row_col = new int[2]; //Holds row and col of uncovered zero. |
| | 316 | boolean done = false; |
| | 317 | while (done == false) |
| | 318 | { |
| | 319 | row_col = findUncoveredZero(row_col, cost, rowCover, colCover); |
| | 320 | if (row_col[0] == -1) |
| | 321 | { |
| | 322 | done = true; |
| | 323 | step = 6; |
| | 324 | } |
| | 325 | else |
| | 326 | { |
| | 327 | mask[row_col[0]][row_col[1]] = 2; //Prime the found uncovered zero. |
| | 328 | |
| | 329 | boolean starInRow = false; |
| | 330 | for (int j=0; j<mask[row_col[0]].length; j++) |
| | 331 | { |
| | 332 | if (mask[row_col[0]][j]==1) //If there is a star in the same row... |
| | 333 | { |
| | 334 | starInRow = true; |
| | 335 | row_col[1] = j; //remember its column. |
| | 336 | } |
| | 337 | } |
| | 338 | |
| | 339 | if (starInRow==true) |
| | 340 | { |
| | 341 | rowCover[row_col[0]] = 1; //Cover the star's row. |
| | 342 | colCover[row_col[1]] = 0; //Uncover its column. |
| | 343 | } |
| | 344 | else |
| | 345 | { |
| | 346 | zero_RC[0] = row_col[0]; //Save row of primed zero. |
| | 347 | zero_RC[1] = row_col[1]; //Save column of primed zero. |
| | 348 | done = true; |
| | 349 | step = 5; |
| | 350 | } |
| | 351 | } |
| | 352 | } |
| | 353 | |
| | 354 | return step; |
| | 355 | } |
| | 356 | public static int[] findUncoveredZero //Aux 1 for hg_step4. |
| | 357 | (int[] row_col, double[][] cost, int[] rowCover, int[] colCover) |
| | 358 | { |
| | 359 | row_col[0] = -1; //Just a check value. Not a real index. |
| | 360 | row_col[1] = 0; |
| | 361 | |
| | 362 | int i = 0; boolean done = false; |
| | 363 | while (done == false) |
| | 364 | { |
| | 365 | int j = 0; |
| | 366 | while (j < cost[i].length) |
| | 367 | { |
| | 368 | if (cost[i][j]==0 && rowCover[i]==0 && colCover[j]==0) |
| | 369 | { |
| | 370 | row_col[0] = i; |
| | 371 | row_col[1] = j; |
| | 372 | done = true; |
| | 373 | } |
| | 374 | j = j+1; |
| | 375 | }//end inner while |
| | 376 | i=i+1; |
| | 377 | if (i >= cost.length) |
| | 378 | { |
| | 379 | done = true; |
| | 380 | } |
| | 381 | }//end outer while |
| | 382 | |
| | 383 | return row_col; |
| | 384 | } |
| | 385 | public static int hg_step5(int step, int[][] mask, int[] rowCover, int[] colCover, int[] zero_RC) |
| | 386 | { |
| | 387 | //What STEP 5 does: |
| | 388 | //Construct series of alternating primes and stars. Start with prime from step 4. |
| | 389 | //Take star in the same column. Next take prime in the same row as the star. Finish |
| | 390 | //at a prime with no star in its column. Unstar all stars and star the primes of the |
| | 391 | //series. Erasy any other primes. Reset covers. Go to step 3. |
| | 392 | |
| | 393 | int count = 0; //Counts rows of the path matrix. |
| | 394 | int[][] path = new int[(mask[0].length*mask.length)][2]; //Path matrix (stores row and col). |
| | 395 | path[count][0] = zero_RC[0]; //Row of last prime. |
| | 396 | path[count][1] = zero_RC[1]; //Column of last prime. |
| | 397 | |
| | 398 | boolean done = false; |
| | 399 | while (done == false) |
| | 400 | { |
| | 401 | int r = findStarInCol(mask, path[count][1]); |
| | 402 | if (r>=0) |
| | 403 | { |
| | 404 | count = count+1; |
| | 405 | path[count][0] = r; //Row of starred zero. |
| | 406 | path[count][1] = path[count-1][1]; //Column of starred zero. |
| | 407 | } |
| | 408 | else |
| | 409 | { |
| | 410 | done = true; |
| | 411 | } |
| | 412 | |
| | 413 | if (done == false) |
| | 414 | { |
| | 415 | int c = findPrimeInRow(mask, path[count][0]); |
| | 416 | count = count+1; |
| | 417 | path[count][0] = path [count-1][0]; //Row of primed zero. |
| | 418 | path[count][1] = c; //Col of primed zero. |
| | 419 | } |
| | 420 | }//end while |
| | 421 | |
| | 422 | convertPath(mask, path, count); |
| | 423 | clearCovers(rowCover, colCover); |
| | 424 | erasePrimes(mask); |
| | 425 | |
| | 426 | step = 3; |
| | 427 | return step; |
| | 428 | |
| | 429 | } |
| | 430 | public static int findStarInCol //Aux 1 for hg_step5. |
| | 431 | (int[][] mask, int col) |
| | 432 | { |
| | 433 | int r=-1; //Again this is a check value. |
| | 434 | for (int i=0; i<mask.length; i++) |
| | 435 | { |
| | 436 | if (mask[i][col]==1) |
| | 437 | { |
| | 438 | r = i; |
| | 439 | } |
| | 440 | } |
| | 441 | |
| | 442 | return r; |
| | 443 | } |
| | 444 | public static int findPrimeInRow //Aux 2 for hg_step5. |
| | 445 | (int[][] mask, int row) |
| | 446 | { |
| | 447 | int c = -1; |
| | 448 | for (int j=0; j<mask[row].length; j++) |
| | 449 | { |
| | 450 | if (mask[row][j]==2) |
| | 451 | { |
| | 452 | c = j; |
| | 453 | } |
| | 454 | } |
| | 455 | |
| | 456 | return c; |
| | 457 | } |
| | 458 | public static void convertPath //Aux 3 for hg_step5. |
| | 459 | (int[][] mask, int[][] path, int count) |
| | 460 | { |
| | 461 | for (int i=0; i<=count; i++) |
| | 462 | { |
| | 463 | if (mask[(path[i][0])][(path[i][1])]==1) |
| | 464 | { |
| | 465 | mask[(path[i][0])][(path[i][1])] = 0; |
| | 466 | } |
| | 467 | else |
| | 468 | { |
| | 469 | mask[(path[i][0])][(path[i][1])] = 1; |
| | 470 | } |
| | 471 | } |
| | 472 | } |
| | 473 | public static void erasePrimes //Aux 4 for hg_step5. |
| | 474 | (int[][] mask) |
| | 475 | { |
| | 476 | for (int i=0; i<mask.length; i++) |
| | 477 | { |
| | 478 | for (int j=0; j<mask[i].length; j++) |
| | 479 | { |
| | 480 | if (mask[i][j]==2) |
| | 481 | { |
| | 482 | mask[i][j] = 0; |
| | 483 | } |
| | 484 | } |
| | 485 | } |
| | 486 | } |
| | 487 | public static void clearCovers //Aux 5 for hg_step5 (and not only). |
| | 488 | (int[] rowCover, int[] colCover) |
| | 489 | { |
| | 490 | for (int i=0; i<rowCover.length; i++) |
| | 491 | { |
| | 492 | rowCover[i] = 0; |
| | 493 | } |
| | 494 | for (int j=0; j<colCover.length; j++) |
| | 495 | { |
| | 496 | colCover[j] = 0; |
| | 497 | } |
| | 498 | } |
| | 499 | public static int hg_step6(int step, double[][] cost, int[] rowCover, int[] colCover, double maxCost) |
| | 500 | { |
| | 501 | //What STEP 6 does: |
| | 502 | //Find smallest uncovered value in cost: a. Add it to every element of covered rows |
| | 503 | //b. Subtract it from every element of uncovered columns. Go to step 4. |
| | 504 | |
| | 505 | double minval = findSmallest(cost, rowCover, colCover, maxCost); |
| | 506 | |
| | 507 | for (int i=0; i<rowCover.length; i++) |
| | 508 | { |
| | 509 | for (int j=0; j<colCover.length; j++) |
| | 510 | { |
| | 511 | if (rowCover[i]==1) |
| | 512 | { |
| | 513 | cost[i][j] = cost[i][j] + minval; |
| | 514 | } |
| | 515 | if (colCover[j]==0) |
| | 516 | { |
| | 517 | cost[i][j] = cost[i][j] - minval; |
| | 518 | } |
| | 519 | } |
| | 520 | } |
| | 521 | |
| | 522 | step = 4; |
| | 523 | return step; |
| | 524 | } |
| | 525 | public static double findSmallest //Aux 1 for hg_step6. |
| | 526 | (double[][] cost, int[] rowCover, int[] colCover, double maxCost) |
| | 527 | { |
| | 528 | double minval = maxCost; //There cannot be a larger cost than this. |
| | 529 | for (int i=0; i<cost.length; i++) //Now find the smallest uncovered value. |
| | 530 | { |
| | 531 | for (int j=0; j<cost[i].length; j++) |
| | 532 | { |
| | 533 | if (rowCover[i]==0 && colCover[j]==0 && (minval > cost[i][j])) |
| | 534 | { |
| | 535 | minval = cost[i][j]; |
| | 536 | } |
| | 537 | } |
| | 538 | } |
| | 539 | |
| | 540 | return minval; |
| | 541 | } |
| | 542 | |
| | 543 | //***********// |
| | 544 | //MAIN METHOD// |
| | 545 | //***********// |
| | 546 | |
| | 547 | public static void main(String[] args) |
| | 548 | { |
| | 549 | //Below enter "max" or "min" to find maximum sum or minimum sum assignment. |
| | 550 | String sumType = "max"; |
| | 551 | |
| | 552 | //Hard-coded example. |
| | 553 | //double[][] array = |
| | 554 | //{ |
| | 555 | // {1, 2, 3}, |
| | 556 | // {2, 4, 6}, |
| | 557 | // {3, 6, 9} |
| | 558 | //}; |
| | 559 | |
| | 560 | //<UNCOMMENT> BELOW AND COMMENT BLOCK ABOVE TO USE A RANDOMLY GENERATED MATRIX |
| | 561 | int numOfRows = readInput("How many rows for the matrix? "); |
| | 562 | int numOfCols = readInput("How many columns for the matrix? "); |
| | 563 | double[][] array = new double[numOfRows][numOfCols]; |
| | 564 | generateRandomArray(array, "random"); //All elements within [0,1]. |
| | 565 | //</UNCOMMENT> |
| | 566 | |
| | 567 | if (array.length > array[0].length) |
| | 568 | { |
| | 569 | System.out.println("Array transposed (because rows>columns).\n"); //Cols must be >= Rows. |
| | 570 | array = transpose(array); |
| | 571 | } |
| | 572 | |
| | 573 | //<COMMENT> TO AVOID PRINTING THE MATRIX FOR WHICH THE ASSIGNMENT IS CALCULATED |
| | 574 | System.out.println("\n(Printing out only 2 decimals)\n"); |
| | 575 | System.out.println("The matrix is:"); |
| | 576 | for (int i=0; i<array.length; i++) |
| | 577 | { |
| | 578 | for (int j=0; j<array[i].length; j++) |
| | 579 | {System.out.printf("%.2f\t", array[i][j]);} |
| | 580 | System.out.println(); |
| | 581 | } |
| | 582 | System.out.println(); |
| | 583 | //</COMMENT>*/ |
| | 584 | |
| | 585 | double startTime = System.nanoTime(); |
| | 586 | int[][] assignment = new int[array.length][2]; |
| | 587 | assignment = hgAlgorithm(array, sumType); //Call Hungarian algorithm. |
| | 588 | double endTime = System.nanoTime(); |
| | 589 | |
| | 590 | System.out.println("The winning assignment (" + sumType + " sum) is:\n"); |
| | 591 | double sum = 0; |
| | 592 | for (int i=0; i<assignment.length; i++) |
| | 593 | { |
| | 594 | //<COMMENT> to avoid printing the elements that make up the assignment |
| | 595 | System.out.printf("array(%d,%d) = %.2f\n", (assignment[i][0]+1), (assignment[i][1]+1), |
| | 596 | array[assignment[i][0]][assignment[i][1]]); |
| | 597 | sum = sum + array[assignment[i][0]][assignment[i][1]]; |
| | 598 | //</COMMENT> |
| | 599 | } |
| | 600 | |
| | 601 | System.out.printf("\nThe %s is: %.2f\n", sumType, sum); |
| | 602 | printTime((endTime - startTime)/1000000000.0); |
| | 603 | |
| | 604 | } |
| | 605 | } |