public object Clone() { var clone = new SolutionCandidate { LowerBound = this.LowerBound, Assignments = new List <int>(this.Assignments) }; return(clone); }
int CalculateLowerBound(SolutionCandidate branch) { var lowerBound = 0; // Add the costs for the already fixed agents: for (var agent = 0; agent < branch.Assignments.Count; agent++) { var task = branch.Assignments[agent]; lowerBound += costMatrix[agent, task]; } // Add "minimum cost" for remaining agents: for (var agent = branch.Assignments.Count; agent < numAgents; agent++) { lowerBound += minimumCosts[agent]; } return(lowerBound); }
public List <int> FindAssignment(out int solutionCost) { // Initialize first solution candidate: var currentSolution = new SolutionCandidate() { Assignments = new List <int>() }; for (var i = 0; i < numAgents; i++) { currentSolution.Assignments.Add(i); currentSolution.LowerBound += costMatrix[i, i]; } // Prepare queue and initialize it with an empty candidate: var queue = new IntervalHeap <SolutionCandidate>(); // A queue or a stack could be used instead. queue.Add(new SolutionCandidate() { Assignments = new List <int>() }); // Here is the main algorithm... while (!queue.IsEmpty) { // Get next candidate. If a priority queue is used, the "next" candidate is the // most promising (with lowest lower bound): var candidate = queue.DeleteMin(); // Branch out: for (var task = 0; task < numTasks; task++) { // Only create the branch if the current task is not already taken by an agent: if (!candidate.Assignments.Contains(task)) // A HashSet on the side could speed up the .Contains() call... { var branch = (SolutionCandidate)candidate.Clone(); branch.Assignments.Add(task); branch.LowerBound = CalculateLowerBound(branch); // Only use the generated branch if its lower bound is strictly better than // the currently found solution cost. // This is the "bound" part in "Branch and Bound": if (branch.LowerBound >= currentSolution.LowerBound) { continue; } // Do we have a solution? if (branch.Assignments.Count == numAgents) { currentSolution = branch; } else // If not, use it for further extension: { queue.Add(branch); } } } } solutionCost = currentSolution.LowerBound; return(currentSolution.Assignments); }