private static int RunStep4(double[,] costs, bool[] rowsCovered, bool[] colsCovered, int w, int h) { if (costs == null) { throw new ArgumentNullException(nameof(costs)); } if (rowsCovered == null) { throw new ArgumentNullException(nameof(rowsCovered)); } if (colsCovered == null) { throw new ArgumentNullException(nameof(colsCovered)); } var minValue = HungarianAlgorithm.FindMinimum(costs, rowsCovered, colsCovered, w, h); for (var i = 0; i < h; i++) { for (var j = 0; j < w; j++) { if (rowsCovered[i]) { costs[i, j] += minValue; } if (!colsCovered[j]) { costs[i, j] -= minValue; } } } return(2); }
private static int RunStep2(double[,] costs, byte[,] masks, bool[] rowsCovered, bool[] colsCovered, int w, int h, ref Location pathStart) { if (costs == null) { throw new ArgumentNullException(nameof(costs)); } if (masks == null) { throw new ArgumentNullException(nameof(masks)); } if (rowsCovered == null) { throw new ArgumentNullException(nameof(rowsCovered)); } if (colsCovered == null) { throw new ArgumentNullException(nameof(colsCovered)); } while (true) { var loc = HungarianAlgorithm.FindZero(costs, rowsCovered, colsCovered, w, h); if (loc.row == -1) { return(4); } masks[loc.row, loc.column] = 2; var starCol = HungarianAlgorithm.FindStarInRow(masks, w, loc.row); if (starCol != -1) { rowsCovered[loc.row] = true; colsCovered[starCol] = false; } else { pathStart = loc; return(3); } } }
private static int RunStep3(byte[,] masks, bool[] rowsCovered, bool[] colsCovered, int w, int h, Location[] path, Location pathStart) { if (masks == null) { throw new ArgumentNullException(nameof(masks)); } if (rowsCovered == null) { throw new ArgumentNullException(nameof(rowsCovered)); } if (colsCovered == null) { throw new ArgumentNullException(nameof(colsCovered)); } var pathIndex = 0; path[0] = pathStart; while (true) { var row = HungarianAlgorithm.FindStarInColumn(masks, h, path[pathIndex].column); if (row == -1) { break; } pathIndex++; path[pathIndex] = new Location(row, path[pathIndex - 1].column); var col = HungarianAlgorithm.FindPrimeInRow(masks, w, path[pathIndex].row); pathIndex++; path[pathIndex] = new Location(path[pathIndex - 1].row, col); } HungarianAlgorithm.ConvertPath(masks, path, pathIndex + 1); HungarianAlgorithm.ClearCovers(rowsCovered, colsCovered, w, h); HungarianAlgorithm.ClearPrimes(masks, w, h); return(1); }
/// <summary> /// Finds the optimal assignments for a given matrix of agents and costed tasks such that the total cost is minimized. /// </summary> /// <param name="costs">A cost matrix; the element at row <em>i</em> and column <em>j</em> represents the cost of agent <em>i</em> performing task <em>j</em>.</param> /// <returns>A matrix of assignments; the value of element <em>i</em> is the column of the task assigned to agent <em>i</em>.</returns> /// <exception cref="ArgumentNullException"><paramref name="costs"/> is null.</exception> public static int[] FindAssignments(this double[,] costs, bool Maximizar) { if (costs == null) { throw new ArgumentNullException(nameof(costs)); } var h = costs.GetLength(0); var w = costs.GetLength(1); if (Maximizar) { for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { costs[i, j] = costs[i, j] * (-1); } } for (var i = 0; i < h; i++) { var min = double.MaxValue; for (var j = 0; j < w; j++) { min = Math.Min(min, costs[i, j]); } for (var j = 0; j < w; j++) { costs[i, j] -= min; } } } else { for (var i = 0; i < h; i++) { var min = double.MaxValue; for (var j = 0; j < w; j++) { min = Math.Min(min, costs[i, j]); } for (var j = 0; j < w; j++) { costs[i, j] -= min; } } } var masks = new byte[h, w]; var rowsCovered = new bool[h]; var colsCovered = new bool[w]; for (var i = 0; i < h; i++) { for (var j = 0; j < w; j++) { if (costs[i, j] == 0 && !rowsCovered[i] && !colsCovered[j]) { masks[i, j] = 1; rowsCovered[i] = true; colsCovered[j] = true; } } } HungarianAlgorithm.ClearCovers(rowsCovered, colsCovered, w, h); var path = new Location[w * h]; var pathStart = default(Location); var step = 1; while (step != -1) { switch (step) { case 1: step = HungarianAlgorithm.RunStep1(masks, colsCovered, w, h); break; case 2: step = HungarianAlgorithm.RunStep2(costs, masks, rowsCovered, colsCovered, w, h, ref pathStart); break; case 3: step = HungarianAlgorithm.RunStep3(masks, rowsCovered, colsCovered, w, h, path, pathStart); break; case 4: step = HungarianAlgorithm.RunStep4(costs, rowsCovered, colsCovered, w, h); break; } } var agentsTasks = new int[h]; for (var i = 0; i < h; i++) { for (var j = 0; j < w; j++) { if (masks[i, j] == 1) { agentsTasks[i] = j; break; } } } return(agentsTasks); }