static void Main() { // Creates the model. // [START model] CpModel model = new CpModel(); // [END model] // Creates the variables. // [START variables] int varUpperBound = new int[] { 50, 45, 37 }.Max(); IntVar x = model.NewIntVar(0, varUpperBound, "x"); IntVar y = model.NewIntVar(0, varUpperBound, "y"); IntVar z = model.NewIntVar(0, varUpperBound, "z"); // [END variables] // Creates the constraints. // [START constraints] model.Add(2 * x + 7 * y + 3 * z <= 50); model.Add(3 * x - 5 * y + 7 * z <= 45); model.Add(5 * x + 2 * y - 6 * z <= 37); // [END constraints] // [START objective] model.Maximize(2 * x + 2 * y + 3 * z); // [END objective] // Creates a solver and solves the model. // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); // [END solve] // [START print_solution] if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine($"Maximum of objective function: {solver.ObjectiveValue}"); Console.WriteLine("x = " + solver.Value(x)); Console.WriteLine("y = " + solver.Value(y)); Console.WriteLine("z = " + solver.Value(z)); } else { Console.WriteLine("No solution found."); } // [END print_solution] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts: {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time: {solver.WallTime()}s"); // [END statistics] }
// [END solution_printer] static void Main() { // Constraint programming engine // [START model] CpModel model = new CpModel(); // [START model] // [START variables] int BoardSize = 8; IntVar[] queens = new IntVar[BoardSize]; for (int i = 0; i < BoardSize; ++i) { queens[i] = model.NewIntVar(0, BoardSize - 1, $"x{i}"); } // [END variables] // Define constraints. // [START constraints] // All rows must be different. model.AddAllDifferent(queens); // All columns must be different because the indices of queens are all different. // No two queens can be on the same diagonal. LinearExpr[] diag1 = new LinearExpr[BoardSize]; LinearExpr[] diag2 = new LinearExpr[BoardSize]; for (int i = 0; i < BoardSize; ++i) { diag1[i] = LinearExpr.Affine(queens[i], /*coeff=*/ 1, /*offset=*/ i); diag2[i] = LinearExpr.Affine(queens[i], /*coeff=*/ 1, /*offset=*/ -i); } model.AddAllDifferent(diag1); model.AddAllDifferent(diag2); // [END constraints] // [START solve] // Creates a solver and solves the model. CpSolver solver = new CpSolver(); SolutionPrinter cb = new SolutionPrinter(queens); // Search for all solutions. solver.StringParameters = "enumerate_all_solutions:true"; // And solve. solver.Solve(model, cb); // [END solve] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts : {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time : {solver.WallTime()} s"); Console.WriteLine($" number of solutions found: {cb.SolutionCount()}"); // [END statistics] }
// [END solution_printer] // Solve the CP+IS+FUN==TRUE cryptarithm. static void Main() { // Constraint programming engine // [START model] CpModel model = new CpModel(); // [START model] // [START variables] int kBase = 10; IntVar c = model.NewIntVar(1, kBase - 1, "C"); IntVar p = model.NewIntVar(0, kBase - 1, "P"); IntVar i = model.NewIntVar(1, kBase - 1, "I"); IntVar s = model.NewIntVar(0, kBase - 1, "S"); IntVar f = model.NewIntVar(1, kBase - 1, "F"); IntVar u = model.NewIntVar(0, kBase - 1, "U"); IntVar n = model.NewIntVar(0, kBase - 1, "N"); IntVar t = model.NewIntVar(1, kBase - 1, "T"); IntVar r = model.NewIntVar(0, kBase - 1, "R"); IntVar e = model.NewIntVar(0, kBase - 1, "E"); // We need to group variables in a list to use the constraint AllDifferent. IntVar[] letters = new IntVar[] { c, p, i, s, f, u, n, t, r, e }; // [END variables] // [START constraints] // Define constraints. model.AddAllDifferent(letters); // CP + IS + FUN = TRUE model.Add(c * kBase + p + i * kBase + s + f * kBase * kBase + u * kBase + n == t * kBase * kBase * kBase + r * kBase * kBase + u * kBase + e); // [END constraints] // [START solve] // Creates a solver and solves the model. CpSolver solver = new CpSolver(); VarArraySolutionPrinter cb = new VarArraySolutionPrinter(letters); // Search for all solutions. solver.StringParameters = "enumerate_all_solutions:true"; // And solve. solver.Solve(model, cb); // [END solve] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts : {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time : {solver.WallTime()} s"); Console.WriteLine($" number of solutions found: {cb.SolutionCount()}"); // [END statistics] }
static void Main() { // Data. int num_nurses = 4; // Nurse assigned to shift 0 means not working that day. int num_shifts = 4; int num_days = 7; var all_nurses = Enumerable.Range(0, num_nurses); var all_shifts = Enumerable.Range(0, num_shifts); var all_working_shifts = Enumerable.Range(1, num_shifts - 1); var all_days = Enumerable.Range(0, num_days); // Creates the model. CpModel model = new CpModel(); // Creates shift variables. // shift[n, d, s]: nurse "n" works shift "s" on day "d". IntVar[,,] shift = new IntVar[num_nurses, num_days, num_shifts]; foreach (int n in all_nurses) { foreach (int d in all_days) { foreach (int s in all_shifts) { shift[n, d, s] = model.NewBoolVar(String.Format("shift_n{0}d{1}s{2}", n, d, s)); } } } // Makes assignments different on each day, that is each shift is // assigned at most one nurse. As we have the same number of // nurses and shifts, then each day, each shift is assigned to // exactly one nurse. foreach (int d in all_days) { foreach (int s in all_shifts) { IntVar[] tmp = new IntVar[num_nurses]; foreach (int n in all_nurses) { tmp[n] = shift[n, d, s]; } model.Add(LinearExpr.Sum(tmp) == 1); } } // Nurses do 1 shift per day. foreach (int n in all_nurses) { foreach (int d in all_days) { IntVar[] tmp = new IntVar[num_shifts]; foreach (int s in all_shifts) { tmp[s] = shift[n, d, s]; } model.Add(LinearExpr.Sum(tmp) == 1); } } // Each nurse works 5 or 6 days in a week. // That is each nurse works shift 0 at most 2 times. foreach (int n in all_nurses) { IntVar[] tmp = new IntVar[num_days]; foreach (int d in all_days) { tmp[d] = shift[n, d, 0]; } model.AddLinearConstraint(LinearExpr.Sum(tmp), 1, 2); } // works_shift[(n, s)] is 1 if nurse n works shift s at least one day in // the week. IntVar[,] works_shift = new IntVar[num_nurses, num_shifts]; foreach (int n in all_nurses) { foreach (int s in all_shifts) { works_shift[n, s] = model.NewBoolVar(String.Format("works_shift_n{0}s{1}", n, s)); IntVar[] tmp = new IntVar[num_days]; foreach (int d in all_days) { tmp[d] = shift[n, d, s]; } model.AddMaxEquality(works_shift[n, s], tmp); } } // For each working shift, at most 2 nurses are assigned to that shift // during the week. foreach (int s in all_working_shifts) { IntVar[] tmp = new IntVar[num_nurses]; foreach (int n in all_nurses) { tmp[n] = works_shift[n, s]; } model.Add(LinearExpr.Sum(tmp) <= 2); } // If a nurse works shifts 2 or 3 on, she must also work that // shift the previous day or the following day. This means that // on a given day and shift, either she does not work that shift // on that day, or she works that shift on the day before, or the // day after. foreach (int n in all_nurses) { for (int s = 2; s <= 3; ++s) { foreach (int d in all_days) { int yesterday = d == 0 ? num_days - 1 : d - 1; int tomorrow = d == num_days - 1 ? 0 : d + 1; model.AddBoolOr( new ILiteral[] { shift[n, yesterday, s], shift[n, d, s].Not(), shift[n, tomorrow, s] }); } } } // Creates the solver and solve. CpSolver solver = new CpSolver(); // Display a few solutions picked at random. HashSet <int> to_print = new HashSet <int>(); to_print.Add(859); to_print.Add(2034); to_print.Add(5091); to_print.Add(7003); NurseSolutionObserver cb = new NurseSolutionObserver(shift, num_nurses, num_days, num_shifts, to_print); CpSolverStatus status = solver.SearchAllSolutions(model, cb); // Statistics. Console.WriteLine("Statistics"); Console.WriteLine(String.Format(" - solve status : {0}", status)); Console.WriteLine(" - conflicts : " + solver.NumConflicts()); Console.WriteLine(" - branches : " + solver.NumBranches()); Console.WriteLine(" - wall time : " + solver.WallTime() + " ms"); Console.WriteLine(" - #solutions : " + cb.SolutionCount()); }
static void Main() { // Data. // [START data_model] int[,] costs = { { 90, 80, 75, 70 }, { 35, 85, 55, 65 }, { 125, 95, 90, 95 }, { 45, 110, 95, 115 }, { 50, 100, 90, 100 }, }; int[] costsFlat = { 90, 80, 75, 70, 35, 85, 55, 65, 125, 95, 90, 95, 45, 110, 95, 115, 50, 100, 90, 100 }; int numWorkers = costs.GetLength(0); int numTasks = costs.GetLength(1); // [END data_model] // Model. // [START model] CpModel model = new CpModel(); // [END model] // Variables. // [START variables] IntVar[,] x = new IntVar[numWorkers, numTasks]; // Variables in a 1-dim array. IntVar[] xFlat = new IntVar[numWorkers * numTasks]; for (int i = 0; i < numWorkers; ++i) { for (int j = 0; j < numTasks; ++j) { x[i, j] = model.NewIntVar(0, 1, $"worker_{i}_task_{j}"); int k = i * numTasks + j; xFlat[k] = x[i, j]; } } // [END variables] // Constraints // [START constraints] // Each worker is assigned to at most one task. int[] onesTasks = { 1, 1, 1, 1 }; for (int i = 0; i < numWorkers; ++i) { IntVar[] vars = new IntVar[numTasks]; for (int j = 0; j < numTasks; ++j) { vars[j] = x[i, j]; } model.Add(LinearExpr.ScalProd(vars, onesTasks) <= 1); } // Each task is assigned to exactly one worker. int[] onesWorkers = { 1, 1, 1, 1, 1 }; for (int j = 0; j < numTasks; ++j) { IntVar[] vars = new IntVar[numWorkers]; for (int i = 0; i < numWorkers; ++i) { vars[i] = x[i, j]; } model.Add(LinearExpr.ScalProd(vars, onesWorkers) == 1); } // [END constraints] // Objective // [START objective] model.Minimize(LinearExpr.ScalProd(xFlat, costsFlat)); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // Print solution. // [START print_solution] // Check that the problem has a feasible solution. if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n"); for (int i = 0; i < numWorkers; ++i) { for (int j = 0; j < numTasks; ++j) { if (solver.Value(x[i, j]) > 0.5) { Console.WriteLine($"Worker {i} assigned to task {j}. Cost: {costs[i, j]}"); } } } } else { Console.WriteLine("No solution found."); } // [END print_solution] Console.WriteLine("Statistics"); Console.WriteLine($" - conflicts : {solver.NumConflicts()}"); Console.WriteLine($" - branches : {solver.NumBranches()}"); Console.WriteLine($" - wall time : {solver.WallTime()}s"); }
public static void Main(String[] args) { // Instantiate the data problem. // [START data] int[] Weights = { 48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36 }; int[] Values = { 10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25 }; int NumItems = Weights.Length; int[] allItems = Enumerable.Range(0, NumItems).ToArray(); int[] BinCapacities = { 100, 100, 100, 100, 100 }; int NumBins = BinCapacities.Length; int[] allBins = Enumerable.Range(0, NumBins).ToArray(); // [END data] // Model. // [START model] CpModel model = new CpModel(); // [END model] // Variables. // [START variables] ILiteral[,] x = new ILiteral[NumItems, NumBins]; foreach (int i in allItems) { foreach (int b in allBins) { x[i, b] = model.NewBoolVar($"x_{i}_{b}"); } } // [END variables] // Constraints. // [START constraints] // Each item is assigned to at most one bin. foreach (int i in allItems) { List <ILiteral> literals = new List <ILiteral>(); foreach (int b in allBins) { literals.Add(x[i, b]); } model.AddAtMostOne(literals); } // The amount packed in each bin cannot exceed its capacity. foreach (int b in allBins) { List <ILiteral> items = new List <ILiteral>(); foreach (int i in allItems) { items.Add(x[i, b]); } model.Add(LinearExpr.WeightedSum(items, Weights) <= BinCapacities[b]); } // [END constraints] // Objective. // [START objective] LinearExprBuilder obj = LinearExpr.NewBuilder(); foreach (int i in allItems) { foreach (int b in allBins) { obj.AddTerm(x[i, b], Values[i]); } } model.Maximize(obj); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); // [END solve] // Print solution. // [START print_solution] // Check that the problem has a feasible solution. if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine($"Total packed value: {solver.ObjectiveValue}"); double TotalWeight = 0.0; foreach (int b in allBins) { double BinWeight = 0.0; double BinValue = 0.0; Console.WriteLine($"Bin {b}"); foreach (int i in allItems) { if (solver.BooleanValue(x[i, b])) { Console.WriteLine($"Item {i} weight: {Weights[i]} values: {Values[i]}"); BinWeight += Weights[i]; BinValue += Values[i]; } } Console.WriteLine("Packed bin weight: " + BinWeight); Console.WriteLine("Packed bin value: " + BinValue); TotalWeight += BinWeight; } Console.WriteLine("Total packed weight: " + TotalWeight); } else { Console.WriteLine("No solution found."); } // [END print_solution] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts: {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time: {solver.WallTime()}s"); // [END statistics] }
public static void Main(String[] args) { // Data. // [START data_model] int[,] costs = { { 90, 80, 75, 70 }, { 35, 85, 55, 65 }, { 125, 95, 90, 95 }, { 45, 110, 95, 115 }, { 50, 100, 90, 100 }, }; int numWorkers = costs.GetLength(0); int numTasks = costs.GetLength(1); // [END data_model] // Model. // [START model] CpModel model = new CpModel(); // [END model] // Variables. // [START variables] BoolVar[,] x = new BoolVar[numWorkers, numTasks]; // Variables in a 1-dim array. for (int worker = 0; worker < numWorkers; ++worker) { for (int task = 0; task < numTasks; ++task) { x[worker, task] = model.NewBoolVar($"worker_{worker}_task_{task}"); } } // [END variables] // Constraints // [START constraints] // Each worker is assigned to at most one task. for (int worker = 0; worker < numWorkers; ++worker) { List <ILiteral> tasks = new List <ILiteral>(); for (int task = 0; task < numTasks; ++task) { tasks.Add(x[worker, task]); } model.AddAtMostOne(tasks); } // Each task is assigned to exactly one worker. for (int task = 0; task < numTasks; ++task) { List <ILiteral> workers = new List <ILiteral>(); for (int worker = 0; worker < numWorkers; ++worker) { workers.Add(x[worker, task]); } model.AddExactlyOne(workers); } // [END constraints] // Objective // [START objective] LinearExprBuilder obj = LinearExpr.NewBuilder(); for (int worker = 0; worker < numWorkers; ++worker) { for (int task = 0; task < numTasks; ++task) { obj.AddTerm((IntVar)x[worker, task], costs[worker, task]); } } model.Minimize(obj); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // Print solution. // [START print_solution] // Check that the problem has a feasible solution. if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n"); for (int i = 0; i < numWorkers; ++i) { for (int j = 0; j < numTasks; ++j) { if (solver.Value(x[i, j]) > 0.5) { Console.WriteLine($"Worker {i} assigned to task {j}. Cost: {costs[i, j]}"); } } } } else { Console.WriteLine("No solution found."); } // [END print_solution] Console.WriteLine("Statistics"); Console.WriteLine($" - conflicts : {solver.NumConflicts()}"); Console.WriteLine($" - branches : {solver.NumBranches()}"); Console.WriteLine($" - wall time : {solver.WallTime()}s"); }
static void BinpackingProblem() { // Data. int bin_capacity = 100; int slack_capacity = 20; int num_bins = 10; int[,] items = new int[, ] { { 20, 12 }, { 15, 12 }, { 30, 8 }, { 45, 5 } }; int num_items = items.GetLength(0); // Model. CpModel model = new CpModel(); // Main variables. IntVar[,] x = new IntVar[num_items, num_bins]; for (int i = 0; i < num_items; ++i) { int num_copies = items[i, 1]; for (int b = 0; b < num_bins; ++b) { x[i, b] = model.NewIntVar(0, num_copies, String.Format("x_{0}_{1}", i, b)); } } // Load variables. IntVar[] load = new IntVar[num_bins]; for (int b = 0; b < num_bins; ++b) { load[b] = model.NewIntVar(0, bin_capacity, String.Format("load_{0}", b)); } // Slack variables. IntVar[] slacks = new IntVar[num_bins]; for (int b = 0; b < num_bins; ++b) { slacks[b] = model.NewBoolVar(String.Format("slack_{0}", b)); } // Links load and x. int[] sizes = new int[num_items]; for (int i = 0; i < num_items; ++i) { sizes[i] = items[i, 0]; } for (int b = 0; b < num_bins; ++b) { IntVar[] tmp = new IntVar[num_items]; for (int i = 0; i < num_items; ++i) { tmp[i] = x[i, b]; } model.Add(load[b] == tmp.ScalProd(sizes)); } // Place all items. for (int i = 0; i < num_items; ++i) { IntVar[] tmp = new IntVar[num_bins]; for (int b = 0; b < num_bins; ++b) { tmp[b] = x[i, b]; } model.Add(tmp.Sum() == items[i, 1]); } // Links load and slack. int safe_capacity = bin_capacity - slack_capacity; for (int b = 0; b < num_bins; ++b) { // slack[b] => load[b] <= safe_capacity. model.Add(load[b] <= safe_capacity).OnlyEnforceIf(slacks[b]); // not(slack[b]) => load[b] > safe_capacity. model.Add(load[b] > safe_capacity).OnlyEnforceIf(slacks[b].Not()); } // Maximize sum of slacks. model.Maximize(slacks.Sum()); // Solves and prints out the solution. CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine(String.Format("Solve status: {0}", status)); if (status == CpSolverStatus.Optimal) { Console.WriteLine(String.Format("Optimal objective value: {0}", solver.ObjectiveValue)); for (int b = 0; b < num_bins; ++b) { Console.WriteLine(String.Format("load_{0} = {1}", b, solver.Value(load[b]))); for (int i = 0; i < num_items; ++i) { Console.WriteLine(string.Format(" item_{0}_{1} = {2}", i, b, solver.Value(x[i, b]))); } } } Console.WriteLine("Statistics"); Console.WriteLine( String.Format(" - conflicts : {0}", solver.NumConflicts())); Console.WriteLine( String.Format(" - branches : {0}", solver.NumBranches())); Console.WriteLine( String.Format(" - wall time : {0} s", solver.WallTime())); }
static void Main() { CpModel model = new CpModel(); int[,] jobs = new[, ] { { 3, 3 }, { 2, 5 }, { 1, 3 }, { 3, 7 }, { 7, 3 }, { 2, 2 }, { 2, 2 }, { 5, 5 }, { 10, 2 }, { 4, 3 }, { 2, 6 }, { 1, 2 }, { 6, 8 }, { 4, 5 }, { 3, 7 } }; int max_length = 10; int num_jobs = jobs.GetLength(0); var all_jobs = Enumerable.Range(0, num_jobs); int horizon = 0; foreach (int j in all_jobs) { horizon += jobs[j, 0]; } List <IntervalVar> intervals = new List <IntervalVar>(); List <IntervalVar> intervals0 = new List <IntervalVar>(); List <IntervalVar> intervals1 = new List <IntervalVar>(); List <IntVar> performed = new List <IntVar>(); List <IntVar> starts = new List <IntVar>(); List <IntVar> ends = new List <IntVar>(); List <int> demands = new List <int>(); foreach (int i in all_jobs) { // Create main interval. IntVar start = model.NewIntVar(0, horizon, String.Format("start_{0}", i)); int duration = jobs[i, 0]; IntVar end = model.NewIntVar(0, horizon, String.Format("end_{0}", i)); IntervalVar interval = model.NewIntervalVar(start, duration, end, String.Format("interval_{0}", i)); starts.Add(start); intervals.Add(interval); ends.Add(end); demands.Add(jobs[i, 1]); IntVar performed_on_m0 = model.NewBoolVar(String.Format("perform_{0}_on_m0", i)); performed.Add(performed_on_m0); // Create an optional copy of interval to be executed on machine 0. IntVar start0 = model.NewIntVar(0, horizon, String.Format("start_{0}_on_m0", i)); IntVar end0 = model.NewIntVar(0, horizon, String.Format("end_{0}_on_m0", i)); IntervalVar interval0 = model.NewOptionalIntervalVar(start0, duration, end0, performed_on_m0, String.Format("interval_{0}_on_m0", i)); intervals0.Add(interval0); // Create an optional copy of interval to be executed on machine 1. IntVar start1 = model.NewIntVar(0, horizon, String.Format("start_{0}_on_m1", i)); IntVar end1 = model.NewIntVar(0, horizon, String.Format("end_{0}_on_m1", i)); IntervalVar interval1 = model.NewOptionalIntervalVar(start1, duration, end1, performed_on_m0.Not(), String.Format("interval_{0}_on_m1", i)); intervals1.Add(interval1); // We only propagate the constraint if the tasks is performed on the // machine. model.Add(start0 == start).OnlyEnforceIf(performed_on_m0); model.Add(start1 == start).OnlyEnforceIf(performed_on_m0.Not()); } // Max Length constraint (modeled as a cumulative) model.AddCumulative(intervals, demands, max_length); // Choose which machine to perform the jobs on. model.AddNoOverlap(intervals0); model.AddNoOverlap(intervals1); // Objective variable. IntVar makespan = model.NewIntVar(0, horizon, "makespan"); model.AddMaxEquality(makespan, ends); model.Minimize(makespan); // Symmetry breaking. model.Add(performed[0] == 0); // Creates the solver and solve. CpSolver solver = new CpSolver(); solver.Solve(model); // Output solution. Console.WriteLine("Solution"); Console.WriteLine(" - makespan = " + solver.ObjectiveValue); foreach (int i in all_jobs) { long performed_machine = 1 - solver.Value(performed[i]); long start = solver.Value(starts[i]); Console.WriteLine(String.Format(" - Job {0} starts at {1} on machine {2}", i, start, performed_machine)); } Console.WriteLine("Statistics"); Console.WriteLine(" - conflicts : " + solver.NumConflicts()); Console.WriteLine(" - branches : " + solver.NumBranches()); Console.WriteLine(" - wall time : " + solver.WallTime() + " ms"); }
// [END assigned_task] public static void Main(String[] args) { // [START data] var allJobs = new[] { new[] { // job0 new { machine = 0, duration = 3 }, // task0 new { machine = 1, duration = 2 }, // task1 new { machine = 2, duration = 2 }, // task2 } .ToList(), new[] { // job1 new { machine = 0, duration = 2 }, // task0 new { machine = 2, duration = 1 }, // task1 new { machine = 1, duration = 4 }, // task2 } .ToList(), new[] { // job2 new { machine = 1, duration = 4 }, // task0 new { machine = 2, duration = 3 }, // task1 } .ToList(), } .ToList(); int numMachines = 0; foreach (var job in allJobs) { foreach (var task in job) { numMachines = Math.Max(numMachines, 1 + task.machine); } } int[] allMachines = Enumerable.Range(0, numMachines).ToArray(); // Computes horizon dynamically as the sum of all durations. int horizon = 0; foreach (var job in allJobs) { foreach (var task in job) { horizon += task.duration; } } // [END data] // Creates the model. // [START model] CpModel model = new CpModel(); // [END model] // [START variables] Dictionary <Tuple <int, int>, Tuple <IntVar, IntVar, IntervalVar> > allTasks = new Dictionary <Tuple <int, int>, Tuple <IntVar, IntVar, IntervalVar> >(); // (start, end, duration) Dictionary <int, List <IntervalVar> > machineToIntervals = new Dictionary <int, List <IntervalVar> >(); for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; for (int taskID = 0; taskID < job.Count(); ++taskID) { var task = job[taskID]; String suffix = $"_{jobID}_{taskID}"; IntVar start = model.NewIntVar(0, horizon, "start" + suffix); IntVar end = model.NewIntVar(0, horizon, "end" + suffix); IntervalVar interval = model.NewIntervalVar(start, task.duration, end, "interval" + suffix); var key = Tuple.Create(jobID, taskID); allTasks[key] = Tuple.Create(start, end, interval); if (!machineToIntervals.ContainsKey(task.machine)) { machineToIntervals.Add(task.machine, new List <IntervalVar>()); } machineToIntervals[task.machine].Add(interval); } } // [END variables] // [START constraints] // Create and add disjunctive constraints. foreach (int machine in allMachines) { model.AddNoOverlap(machineToIntervals[machine]); } // Precedences inside a job. for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; for (int taskID = 0; taskID < job.Count() - 1; ++taskID) { var key = Tuple.Create(jobID, taskID); var nextKey = Tuple.Create(jobID, taskID + 1); model.Add(allTasks[nextKey].Item1 >= allTasks[key].Item2); } } // [END constraints] // [START objective] // Makespan objective. IntVar objVar = model.NewIntVar(0, horizon, "makespan"); List <IntVar> ends = new List <IntVar>(); for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; var key = Tuple.Create(jobID, job.Count() - 1); ends.Add(allTasks[key].Item2); } model.AddMaxEquality(objVar, ends); model.Minimize(objVar); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // [START print_solution] if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine("Solution:"); Dictionary <int, List <AssignedTask> > assignedJobs = new Dictionary <int, List <AssignedTask> >(); for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; for (int taskID = 0; taskID < job.Count(); ++taskID) { var task = job[taskID]; var key = Tuple.Create(jobID, taskID); int start = (int)solver.Value(allTasks[key].Item1); if (!assignedJobs.ContainsKey(task.machine)) { assignedJobs.Add(task.machine, new List <AssignedTask>()); } assignedJobs[task.machine].Add(new AssignedTask(jobID, taskID, start, task.duration)); } } // Create per machine output lines. String output = ""; foreach (int machine in allMachines) { // Sort by starting time. assignedJobs[machine].Sort(); String solLineTasks = $"Machine {machine}: "; String solLine = " "; foreach (var assignedTask in assignedJobs[machine]) { String name = $"job_{assignedTask.jobID}_task_{assignedTask.taskID}"; // Add spaces to output to align columns. solLineTasks += $"{name,-15}"; String solTmp = $"[{assignedTask.start},{assignedTask.start+assignedTask.duration}]"; // Add spaces to output to align columns. solLine += $"{solTmp,-15}"; } output += solLineTasks + "\n"; output += solLine + "\n"; } // Finally print the solution found. Console.WriteLine($"Optimal Schedule Length: {solver.ObjectiveValue}"); Console.WriteLine($"\n{output}"); } else { Console.WriteLine("No solution found."); } // [END print_solution] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts: {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time: {solver.WallTime()}s"); // [END statistics] }
public static void Main(String[] args) { // [START data] const int numNurses = 5; const int numDays = 7; const int numShifts = 3; int[] allNurses = Enumerable.Range(0, numNurses).ToArray(); int[] allDays = Enumerable.Range(0, numDays).ToArray(); int[] allShifts = Enumerable.Range(0, numShifts).ToArray(); int[,,] shiftRequests = new int[, , ] { { { 0, 0, 1 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 }, { 0, 0, 1 }, }, { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 0 }, { 0, 0, 1 }, }, { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 0, 0 }, { 1, 0, 0 }, { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 }, }, { { 0, 0, 1 }, { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 }, { 1, 0, 0 }, { 0, 0, 0 }, }, { { 0, 0, 0 }, { 0, 0, 1 }, { 0, 1, 0 }, { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 }, }, }; // [END data] // Creates the model. // [START model] CpModel model = new CpModel(); // [END model] // Creates shift variables. // shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'. // [START variables] Dictionary <Tuple <int, int, int>, IntVar> shifts = new Dictionary <Tuple <int, int, int>, IntVar>(); foreach (int n in allNurses) { foreach (int d in allDays) { foreach (int s in allShifts) { shifts.Add(Tuple.Create(n, d, s), model.NewBoolVar($"shifts_n{n}d{d}s{s}")); } } } // [END variables] // Each shift is assigned to exactly one nurse in the schedule period. // [START exactly_one_nurse] foreach (int d in allDays) { foreach (int s in allShifts) { IntVar[] x = new IntVar[numNurses]; foreach (int n in allNurses) { var key = Tuple.Create(n, d, s); x[n] = shifts[key]; } model.Add(LinearExpr.Sum(x) == 1); } } // [END exactly_one_nurse] // Each nurse works at most one shift per day. // [START at_most_one_shift] foreach (int n in allNurses) { foreach (int d in allDays) { IntVar[] x = new IntVar[numShifts]; foreach (int s in allShifts) { var key = Tuple.Create(n, d, s); x[s] = shifts[key]; } model.Add(LinearExpr.Sum(x) <= 1); } } // [END at_most_one_shift] // [START assign_nurses_evenly] // Try to distribute the shifts evenly, so that each nurse works // minShiftsPerNurse shifts. If this is not possible, because the total // number of shifts is not divisible by the number of nurses, some nurses will // be assigned one more shift. int minShiftsPerNurse = (numShifts * numDays) / numNurses; int maxShiftsPerNurse; if ((numShifts * numDays) % numNurses == 0) { maxShiftsPerNurse = minShiftsPerNurse; } else { maxShiftsPerNurse = minShiftsPerNurse + 1; } foreach (int n in allNurses) { IntVar[] numShiftsWorked = new IntVar[numDays * numShifts]; foreach (int d in allDays) { foreach (int s in allShifts) { var key = Tuple.Create(n, d, s); numShiftsWorked[d * numShifts + s] = shifts[key]; } } model.AddLinearConstraint(LinearExpr.Sum(numShiftsWorked), minShiftsPerNurse, maxShiftsPerNurse); } // [END assign_nurses_evenly] // [START objective] IntVar[] flatShifts = new IntVar[numNurses * numDays * numShifts]; int[] flatShiftRequests = new int[numNurses * numDays * numShifts]; foreach (int n in allNurses) { foreach (int d in allDays) { foreach (int s in allShifts) { var key = Tuple.Create(n, d, s); flatShifts[n * numDays * numShifts + d * numShifts + s] = shifts[key]; flatShiftRequests[n * numDays * numShifts + d * numShifts + s] = shiftRequests[n, d, s]; } } } model.Maximize(LinearExpr.ScalProd(flatShifts, flatShiftRequests)); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // [START print_solution] if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine("Solution:"); foreach (int d in allDays) { Console.WriteLine($"Day {d}"); foreach (int n in allNurses) { bool isWorking = false; foreach (int s in allShifts) { var key = Tuple.Create(n, d, s); if (solver.Value(shifts[key]) == 1L) { if (shiftRequests[n, d, s] == 1) { Console.WriteLine($" Nurse {n} work shift {s} (requested)."); } else { Console.WriteLine($" Nurse {n} work shift {s} (not requested)."); } } } } } Console.WriteLine( $"Number of shift requests met = {solver.ObjectiveValue} (out of {numNurses * minShiftsPerNurse})."); } else { Console.WriteLine("No solution found."); } // [END print_solution] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts: {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time: {solver.WallTime()}s"); // [END statistics] }
// [END solution_printer] public static void Main(String[] args) { // [START data] const int numNurses = 4; const int numDays = 3; const int numShifts = 3; int[] allNurses = Enumerable.Range(0, numNurses).ToArray(); int[] allDays = Enumerable.Range(0, numDays).ToArray(); int[] allShifts = Enumerable.Range(0, numShifts).ToArray(); // [END data] // Creates the model. // [START model] CpModel model = new CpModel(); // [END model] // Creates shift variables. // shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'. // [START variables] Dictionary <Tuple <int, int, int>, IntVar> shifts = new Dictionary <Tuple <int, int, int>, IntVar>(); foreach (int n in allNurses) { foreach (int d in allDays) { foreach (int s in allShifts) { shifts.Add(Tuple.Create(n, d, s), model.NewBoolVar($"shifts_n{n}d{d}s{s}")); } } } // [END variables] // Each shift is assigned to exactly one nurse in the schedule period. // [START exactly_one_nurse] foreach (int d in allDays) { foreach (int s in allShifts) { IntVar[] x = new IntVar[numNurses]; foreach (int n in allNurses) { var key = Tuple.Create(n, d, s); x[n] = shifts[key]; } model.Add(LinearExpr.Sum(x) == 1); } } // [END exactly_one_nurse] // Each nurse works at most one shift per day. // [START at_most_one_shift] foreach (int n in allNurses) { foreach (int d in allDays) { IntVar[] x = new IntVar[numShifts]; foreach (int s in allShifts) { var key = Tuple.Create(n, d, s); x[s] = shifts[key]; } model.Add(LinearExpr.Sum(x) <= 1); } } // [END at_most_one_shift] // [START assign_nurses_evenly] // Try to distribute the shifts evenly, so that each nurse works // minShiftsPerNurse shifts. If this is not possible, because the total // number of shifts is not divisible by the number of nurses, some nurses will // be assigned one more shift. int minShiftsPerNurse = (numShifts * numDays) / numNurses; int maxShiftsPerNurse; if ((numShifts * numDays) % numNurses == 0) { maxShiftsPerNurse = minShiftsPerNurse; } else { maxShiftsPerNurse = minShiftsPerNurse + 1; } foreach (int n in allNurses) { IntVar[] numShiftsWorked = new IntVar[numDays * numShifts]; foreach (int d in allDays) { foreach (int s in allShifts) { var key = Tuple.Create(n, d, s); numShiftsWorked[d * numShifts + s] = shifts[key]; } } model.AddLinearConstraint(LinearExpr.Sum(numShiftsWorked), minShiftsPerNurse, maxShiftsPerNurse); } // [END assign_nurses_evenly] // [START parameters] CpSolver solver = new CpSolver(); solver.StringParameters += "linearization_level:0 "; // Tell the solver to enumerate all solutions. solver.StringParameters += "enumerate_all_solutions:true "; // [END parameters] // Display the first five solutions. // [START solution_printer_instantiate] const int solutionLimit = 5; SolutionPrinter cb = new SolutionPrinter(allNurses, allDays, allShifts, shifts, solutionLimit); // [END solution_printer_instantiate] // Solve // [START solve] CpSolverStatus status = solver.Solve(model, cb); Console.WriteLine($"Solve status: {status}"); // [END solve] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts: {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time: {solver.WallTime()}s"); // [END statistics] }
public static void Main(String[] args) { // Data. // [START data] int[,] costs = { { 90, 76, 75, 70, 50, 74, 12, 68 }, { 35, 85, 55, 65, 48, 101, 70, 83 }, { 125, 95, 90, 105, 59, 120, 36, 73 }, { 45, 110, 95, 115, 104, 83, 37, 71 }, { 60, 105, 80, 75, 59, 62, 93, 88 }, { 45, 65, 110, 95, 47, 31, 81, 34 }, { 38, 51, 107, 41, 69, 99, 115, 48 }, { 47, 85, 57, 71, 92, 77, 109, 36 }, { 39, 63, 97, 49, 118, 56, 92, 61 }, { 47, 101, 71, 60, 88, 109, 52, 90 }, }; int numWorkers = costs.GetLength(0); int numTasks = costs.GetLength(1); int[] allWorkers = Enumerable.Range(0, numWorkers).ToArray(); int[] allTasks = Enumerable.Range(0, numTasks).ToArray(); int[] taskSizes = { 10, 7, 3, 12, 15, 4, 11, 5 }; // Maximum total of task sizes for any worker int totalSizeMax = 15; // [END data] // Model. // [START model] CpModel model = new CpModel(); // [END model] // Variables. // [START variables] BoolVar[,] x = new BoolVar[numWorkers, numTasks]; foreach (int worker in allWorkers) { foreach (int task in allTasks) { x[worker, task] = model.NewBoolVar($"x[{worker},{task}]"); } } // [END variables] // Constraints // [START constraints] // Each worker is assigned to at most max task size. foreach (int worker in allWorkers) { BoolVar[] vars = new BoolVar[numTasks]; foreach (int task in allTasks) { vars[task] = x[worker, task]; } model.Add(LinearExpr.WeightedSum(vars, taskSizes) <= totalSizeMax); } // Each task is assigned to exactly one worker. foreach (int task in allTasks) { List <ILiteral> workers = new List <ILiteral>(); foreach (int worker in allWorkers) { workers.Add(x[worker, task]); } model.AddExactlyOne(workers); } // [END constraints] // Objective // [START objective] LinearExprBuilder obj = LinearExpr.NewBuilder(); foreach (int worker in allWorkers) { foreach (int task in allTasks) { obj.AddTerm(x[worker, task], costs[worker, task]); } } model.Minimize(obj); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // Print solution. // [START print_solution] // Check that the problem has a feasible solution. if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n"); foreach (int worker in allWorkers) { foreach (int task in allTasks) { if (solver.Value(x[worker, task]) > 0.5) { Console.WriteLine($"Worker {worker} assigned to task {task}. " + $"Cost: {costs[worker, task]}"); } } } } else { Console.WriteLine("No solution found."); } // [END print_solution] Console.WriteLine("Statistics"); Console.WriteLine($" - conflicts : {solver.NumConflicts()}"); Console.WriteLine($" - branches : {solver.NumBranches()}"); Console.WriteLine($" - wall time : {solver.WallTime()}s"); }
static void Solve() { int[,] durations = new int[, ] { { 1, 3, 6, 7, 3, 6 }, { 8, 5, 10, 10, 10, 4 }, { 5, 4, 8, 9, 1, 7 }, { 5, 5, 5, 3, 8, 9 }, { 9, 3, 5, 4, 3, 1 }, { 3, 3, 9, 10, 4, 1 } }; int[,] machines = new int[, ] { { 2, 0, 1, 3, 5, 4 }, { 1, 2, 4, 5, 0, 3 }, { 2, 3, 5, 0, 1, 4 }, { 1, 0, 2, 3, 4, 5 }, { 2, 1, 4, 5, 0, 3 }, { 1, 3, 5, 0, 4, 2 } }; int num_jobs = durations.GetLength(0); int num_machines = durations.GetLength(1); var all_jobs = Enumerable.Range(0, num_jobs); var all_machines = Enumerable.Range(0, num_machines); int horizon = 0; foreach (int j in all_jobs) { foreach (int m in all_machines) { horizon += durations[j, m]; } } // Creates the model. CpModel model = new CpModel(); // Creates jobs. Task[,] all_tasks = new Task[num_jobs, num_machines]; foreach (int j in all_jobs) { foreach (int m in all_machines) { IntVar start_var = model.NewIntVar( 0, horizon, String.Format("start_{0}_{1}", j, m)); int duration = durations[j, m]; IntVar end_var = model.NewIntVar( 0, horizon, String.Format("end_{0}_{1}", j, m)); IntervalVar interval_var = model.NewIntervalVar( start_var, duration, end_var, String.Format("interval_{0}_{1}", j, m)); all_tasks[j, m] = new Task(start_var, end_var, interval_var); } } // Create disjuctive constraints. List <IntervalVar>[] machine_to_jobs = new List <IntervalVar> [num_machines]; foreach (int m in all_machines) { machine_to_jobs[m] = new List <IntervalVar>(); } foreach (int j in all_jobs) { foreach (int m in all_machines) { machine_to_jobs[machines[j, m]].Add(all_tasks[j, m].interval); } } foreach (int m in all_machines) { model.AddNoOverlap(machine_to_jobs[m]); } // Precedences inside a job. foreach (int j in all_jobs) { for (int k = 0; k < num_machines - 1; ++k) { model.Add(all_tasks[j, k + 1].start >= all_tasks[j, k].end); } } // Makespan objective. IntVar[] all_ends = new IntVar[num_jobs]; foreach (int j in all_jobs) { all_ends[j] = all_tasks[j, num_machines - 1].end; } IntVar makespan = model.NewIntVar(0, horizon, "makespan"); model.AddMaxEquality(makespan, all_ends); model.Minimize(makespan); // Creates the solver and solve. CpSolver solver = new CpSolver(); // Display a few solutions picked at random. CpSolverStatus status = solver.Solve(model); // Statistics. Console.WriteLine("Statistics"); Console.WriteLine(String.Format(" - solve status : {0}", status)); Console.WriteLine(" - makespan : " + solver.ObjectiveValue); Console.WriteLine(" - conflicts : " + solver.NumConflicts()); Console.WriteLine(" - branches : " + solver.NumBranches()); Console.WriteLine(" - wall time : " + solver.WallTime() + " ms"); }
public static void Main(String[] args) { // Data. // [START data] int[,] costs = { { 90, 76, 75, 70, 50, 74 }, { 35, 85, 55, 65, 48, 101 }, { 125, 95, 90, 105, 59, 120 }, { 45, 110, 95, 115, 104, 83 }, { 60, 105, 80, 75, 59, 62 }, { 45, 65, 110, 95, 47, 31 }, { 38, 51, 107, 41, 69, 99 }, { 47, 85, 57, 71, 92, 77 }, { 39, 63, 97, 49, 118, 56 }, { 47, 101, 71, 60, 88, 109 }, { 17, 39, 103, 64, 61, 92 }, { 101, 45, 83, 59, 92, 27 }, }; int numWorkers = costs.GetLength(0); int numTasks = costs.GetLength(1); int[] allWorkers = Enumerable.Range(0, numWorkers).ToArray(); int[] allTasks = Enumerable.Range(0, numTasks).ToArray(); // [END data] // Allowed groups of workers: // [START allowed_groups] long[,] group1 = { { 0, 0, 1, 1 }, // Workers 2, 3 { 0, 1, 0, 1 }, // Workers 1, 3 { 0, 1, 1, 0 }, // Workers 1, 2 { 1, 1, 0, 0 }, // Workers 0, 1 { 1, 0, 1, 0 }, // Workers 0, 2 }; long[,] group2 = { { 0, 0, 1, 1 }, // Workers 6, 7 { 0, 1, 0, 1 }, // Workers 5, 7 { 0, 1, 1, 0 }, // Workers 5, 6 { 1, 1, 0, 0 }, // Workers 4, 5 { 1, 0, 0, 1 }, // Workers 4, 7 }; long[,] group3 = { { 0, 0, 1, 1 }, // Workers 10, 11 { 0, 1, 0, 1 }, // Workers 9, 11 { 0, 1, 1, 0 }, // Workers 9, 10 { 1, 0, 1, 0 }, // Workers 8, 10 { 1, 0, 0, 1 }, // Workers 8, 11 }; // [END allowed_groups] // Model. // [START model] CpModel model = new CpModel(); // [END model] // Variables. // [START variables] BoolVar[,] x = new BoolVar[numWorkers, numTasks]; // Variables in a 1-dim array. foreach (int worker in allWorkers) { foreach (int task in allTasks) { x[worker, task] = model.NewBoolVar($"x[{worker},{task}]"); } } // [END variables] // Constraints // [START constraints] // Each worker is assigned to at most one task. foreach (int worker in allWorkers) { List <ILiteral> tasks = new List <ILiteral>(); foreach (int task in allTasks) { tasks.Add(x[worker, task]); } model.AddAtMostOne(tasks); } // Each task is assigned to exactly one worker. foreach (int task in allTasks) { List <ILiteral> workers = new List <ILiteral>(); foreach (int worker in allWorkers) { workers.Add(x[worker, task]); } model.AddExactlyOne(workers); } // [END constraints] // [START assignments] // Create variables for each worker, indicating whether they work on some task. BoolVar[] work = new BoolVar[numWorkers]; foreach (int worker in allWorkers) { work[worker] = model.NewBoolVar($"work[{worker}]"); } foreach (int worker in allWorkers) { List <ILiteral> tasks = new List <ILiteral>(); foreach (int task in allTasks) { tasks.Add(x[worker, task]); } model.Add(work[worker] == LinearExpr.Sum(tasks)); } // Define the allowed groups of worders model.AddAllowedAssignments(new IntVar[] { work[0], work[1], work[2], work[3] }).AddTuples(group1); model.AddAllowedAssignments(new IntVar[] { work[4], work[5], work[6], work[7] }).AddTuples(group2); model.AddAllowedAssignments(new IntVar[] { work[8], work[9], work[10], work[11] }).AddTuples(group3); // [END assignments] // Objective // [START objective] LinearExprBuilder obj = LinearExpr.NewBuilder(); foreach (int worker in allWorkers) { foreach (int task in allTasks) { obj.AddTerm(x[worker, task], costs[worker, task]); } } model.Minimize(obj); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // Print solution. // [START print_solution] // Check that the problem has a feasible solution. if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n"); foreach (int worker in allWorkers) { foreach (int task in allTasks) { if (solver.Value(x[worker, task]) > 0.5) { Console.WriteLine($"Worker {worker} assigned to task {task}. " + $"Cost: {costs[worker, task]}"); } } } } else { Console.WriteLine("No solution found."); } // [END print_solution] Console.WriteLine("Statistics"); Console.WriteLine($" - conflicts : {solver.NumConflicts()}"); Console.WriteLine($" - branches : {solver.NumBranches()}"); Console.WriteLine($" - wall time : {solver.WallTime()}s"); }
public static void Main(String[] args) { // Data. // [START data] int[,] costs = { { 90, 76, 75, 70 }, { 35, 85, 55, 65 }, { 125, 95, 90, 105 }, { 45, 110, 95, 115 }, { 60, 105, 80, 75 }, { 45, 65, 110, 95 }, }; int numWorkers = costs.GetLength(0); int numTasks = costs.GetLength(1); int[] allWorkers = Enumerable.Range(0, numWorkers).ToArray(); int[] allTasks = Enumerable.Range(0, numTasks).ToArray(); int[] team1 = { 0, 2, 4 }; int[] team2 = { 1, 3, 5 }; // Maximum total of tasks for any team int teamMax = 2; // [END data] // Model. // [START model] CpModel model = new CpModel(); // [END model] // Variables. // [START variables] BoolVar[,] x = new BoolVar[numWorkers, numTasks]; foreach (int worker in allWorkers) { foreach (int task in allTasks) { x[worker, task] = model.NewBoolVar($"x[{worker},{task}]"); } } // [END variables] // Constraints // [START constraints] // Each worker is assigned to at most one task. foreach (int worker in allWorkers) { List <ILiteral> tasks = new List <ILiteral>(); foreach (int task in allTasks) { tasks.Add(x[worker, task]); } model.AddAtMostOne(tasks); } // Each task is assigned to exactly one worker. foreach (int task in allTasks) { List <ILiteral> workers = new List <ILiteral>(); foreach (int worker in allWorkers) { workers.Add(x[worker, task]); } model.AddExactlyOne(workers); } // Each team takes at most two tasks. List <IntVar> team1Tasks = new List <IntVar>(); foreach (int worker in team1) { foreach (int task in allTasks) { team1Tasks.Add(x[worker, task]); } } model.Add(LinearExpr.Sum(team1Tasks.ToArray()) <= teamMax); List <IntVar> team2Tasks = new List <IntVar>(); foreach (int worker in team2) { foreach (int task in allTasks) { team2Tasks.Add(x[worker, task]); } } model.Add(LinearExpr.Sum(team2Tasks.ToArray()) <= teamMax); // [END constraints] // Objective // [START objective] LinearExprBuilder obj = LinearExpr.NewBuilder(); foreach (int worker in allWorkers) { foreach (int task in allTasks) { obj.AddTerm(x[worker, task], costs[worker, task]); } } model.Minimize(obj); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // Print solution. // [START print_solution] // Check that the problem has a feasible solution. if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n"); foreach (int worker in allWorkers) { foreach (int task in allTasks) { if (solver.Value(x[worker, task]) > 0.5) { Console.WriteLine($"Worker {worker} assigned to task {task}. " + $"Cost: {costs[worker, task]}"); } } } } else { Console.WriteLine("No solution found."); } // [END print_solution] Console.WriteLine("Statistics"); Console.WriteLine($" - conflicts : {solver.NumConflicts()}"); Console.WriteLine($" - branches : {solver.NumBranches()}"); Console.WriteLine($" - wall time : {solver.WallTime()}s"); }