static void Main(string[] args) { var parameters = new Parameters(new Randomizer(), args); if (parameters.ShowHelp) { var helpPrinter = new HelpPrinter(); helpPrinter.Print(); } else { var verbosePrinter = new VerbosePrinter(parameters.IsVerboseEnabled); var calculator = new Calculator(verbosePrinter, parameters.Target, parameters.Numbers); if (parameters.IsUsingRandomTarget) { Console.WriteLine("No target number specified. Will use random number."); Console.WriteLine($"The random target is {calculator.Target}"); Console.WriteLine(); } if (parameters.IsUsingRandomNumbers) { Console.WriteLine("No numbers specified. Will use random numbers between 1 and 20."); var numbers = string.Join(", ", calculator.InputNumbers.Select(o => o.Integer.ToString())); Console.WriteLine($"The numbers are {numbers}"); Console.WriteLine(); } var result = calculator.FindSolutions(); var printer = new SolutionPrinter(parameters.ShowAllResults, result); printer.Print(); } }
// [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] }
static void Main(string[] args) { int numberGroups = 10; int numberItems = 100; int numberColors = 3; int minItemsOfSameColorPerGroup = 4; var allGroups = Enumerable.Range(0, numberGroups).ToArray(); var allItems = Enumerable.Range(0, numberItems).ToArray(); var allColors = Enumerable.Range(0, numberColors).ToArray(); var values = allItems.Select(i => 1 + i + (i * i / 200)).ToArray(); var colors = allItems.Select(i => i % numberColors).ToArray(); var sumOfValues = values.Sum(); var averageSumPerGroup = sumOfValues / numberGroups; var numItemsPerGroup = numberItems / numberGroups; var itemsPerColor = new Dictionary <int, List <int> >(); foreach (var color in allColors) { itemsPerColor[color] = new List <int>(); foreach (var item in allItems) { if (colors[item] == color) { itemsPerColor[color].Add(item); } } } Console.WriteLine($"Model has {numberItems}, {numberGroups} groups and {numberColors} colors"); Console.WriteLine($" Average sum per group = {averageSumPerGroup}"); var model = new CpModel(); var itemInGroup = new IntVar[numberItems, numberGroups]; foreach (var item in allItems) { foreach (var @group in allGroups) { itemInGroup[item, @group] = model.NewBoolVar($"item {item} in group {@group}"); } } // Each group must have the same size. foreach (var @group in allGroups) { var itemsInGroup = allItems.Select(x => itemInGroup[x, @group]).ToArray(); model.AddLinearConstraint(LinearExpr.Sum(itemsInGroup), numItemsPerGroup, numItemsPerGroup); } //# One item must belong to exactly one group. foreach (var item in allItems) { var groupsForItem = allGroups.Select(x => itemInGroup[item, x]).ToArray(); model.Add(LinearExpr.Sum(groupsForItem) == 1); } // The deviation of the sum of each items in a group against the average. var e = model.NewIntVar(0, 550, "epsilon"); // Constrain the sum of values in one group around the average sum per // group. foreach (var @group in allGroups) { var itemValues = allItems.Select(x => itemInGroup[x, @group]).ToArray(); var sum = LinearExpr.ScalProd(itemValues, values); model.Add(sum <= averageSumPerGroup + e); model.Add(sum >= averageSumPerGroup - e); } // colorInGroup variables. var colorInGroup = new IntVar[numberColors, numberGroups]; foreach (var @group in allGroups) { foreach (var color in allColors) { colorInGroup[color, @group] = model.NewBoolVar($"color {color} is in group {@group}"); } } // Item is in a group implies its color is in that group. foreach (var item in allItems) { foreach (var @group in allGroups) { model.AddImplication(itemInGroup[item, @group], colorInGroup[colors[item], @group]); } } // If a color is in a group, it must contains at least // min_items_of_same_color_per_group items from that color. foreach (var color in allColors) { foreach (var @group in allGroups) { var literal = colorInGroup[color, @group]; var items = itemsPerColor[color].Select(x => itemInGroup[x, @group]).ToArray(); model.Add(LinearExpr.Sum(items) >= minItemsOfSameColorPerGroup).OnlyEnforceIf(literal); } } // Compute the maximum number of colors in a group. int maxColor = numItemsPerGroup / minItemsOfSameColorPerGroup; // Redundant contraint: The problem does not solve in reasonable time // without it. if (maxColor < numberColors) { foreach (var @group in allGroups) { var all = allColors.Select(x => colorInGroup[x, @group]).ToArray(); model.Add(LinearExpr.Sum(all) <= maxColor); } } // Minimize epsilon model.Minimize(e); var solver = new CpSolver(); var solutionPrinter = new SolutionPrinter(values, colors, allGroups, allItems, itemInGroup); var status = solver.SolveWithSolutionCallback(model, solutionPrinter); }
// [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] }