/** * * Solves the Minesweeper problems. * * See http://www.hakank.org/google_or_tools/minesweeper.py * */ private static void Solve() { Solver solver = new Solver("Minesweeper"); // // data // int[] S = { -1, 0, 1 }; Console.WriteLine("Problem:"); for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (game[i, j] > X) { Console.Write(game[i, j] + " "); } else { Console.Write("X "); } } Console.WriteLine(); } Console.WriteLine(); // // Decision variables // IntVar[,] mines = solver.MakeIntVarMatrix(r, c, 0, 1, "mines"); // for branching IntVar[] mines_flat = mines.Flatten(); // // Constraints // for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (game[i, j] >= 0) { solver.Add(mines[i, j] == 0); // this cell is the sum of all its neighbours var tmp = from a in S from b in S where i + a >= 0 && j + b >= 0 && i + a < r && j + b < c select(mines[i + a, j + b]); solver.Add(tmp.ToArray().Sum() == game[i, j]); } if (game[i, j] > X) { // This cell cannot be a mine since it // has some value assigned to it solver.Add(mines[i, j] == 0); } } } // // Search // DecisionBuilder db = solver.MakePhase(mines_flat, Solver.CHOOSE_PATH, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db); int sol = 0; while (solver.NextSolution()) { sol++; Console.WriteLine("Solution #{0} ", sol + " "); for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { Console.Write("{0} ", mines[i, j].Value()); } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
public static void Main(String[] args) { // Instantiate the solver. // [START solver] Solver solver = new Solver("CP is fun!"); // [END solver] // [START variables] const int kBase = 10; // Decision variables. IntVar c = solver.MakeIntVar(1, kBase - 1, "C"); IntVar p = solver.MakeIntVar(0, kBase - 1, "P"); IntVar i = solver.MakeIntVar(1, kBase - 1, "I"); IntVar s = solver.MakeIntVar(0, kBase - 1, "S"); IntVar f = solver.MakeIntVar(1, kBase - 1, "F"); IntVar u = solver.MakeIntVar(0, kBase - 1, "U"); IntVar n = solver.MakeIntVar(0, kBase - 1, "N"); IntVar t = solver.MakeIntVar(1, kBase - 1, "T"); IntVar r = solver.MakeIntVar(0, kBase - 1, "R"); IntVar e = solver.MakeIntVar(0, kBase - 1, "E"); // Group variables in a vector so that we can use AllDifferent. IntVar[] letters = new IntVar[] { c, p, i, s, f, u, n, t, r, e }; // Verify that we have enough digits. if (kBase < letters.Length) { throw new Exception("kBase < letters.Length"); } // [END variables] // Define constraints. // [START constraints] solver.Add(letters.AllDifferent()); // CP + IS + FUN = TRUE solver.Add(p + s + n + kBase * (c + i + u) + kBase * kBase * f == e + kBase * u + kBase * kBase * r + kBase * kBase * kBase * t); // [END constraints] // [START solve] int SolutionCount = 0; // Create the decision builder to search for solutions. DecisionBuilder db = solver.MakePhase(letters, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db); while (solver.NextSolution()) { Console.Write("C=" + c.Value() + " P=" + p.Value()); Console.Write(" I=" + i.Value() + " S=" + s.Value()); Console.Write(" F=" + f.Value() + " U=" + u.Value()); Console.Write(" N=" + n.Value() + " T=" + t.Value()); Console.Write(" R=" + r.Value() + " E=" + e.Value()); Console.WriteLine(); // Is CP + IS + FUN = TRUE? if (p.Value() + s.Value() + n.Value() + kBase * (c.Value() + i.Value() + u.Value()) + kBase * kBase * f.Value() != e.Value() + kBase * u.Value() + kBase * kBase * r.Value() + kBase * kBase * kBase * t.Value()) { throw new Exception("CP + IS + FUN != TRUE"); } SolutionCount++; } solver.EndSearch(); Console.WriteLine($"Number of solutions found: {SolutionCount}"); // [END solve] }
/** * * Rogo puzzle solver. * * From http://www.rogopuzzle.co.nz/ * """ * The object is to collect the biggest score possible using a given * number of steps in a loop around a grid. The best possible score * for a puzzle is given with it, so you can easily check that you have * solved the puzzle. Rogo puzzles can also include forbidden squares, * which must be avoided in your loop. * """ * * Also see Mike Trick: * "Operations Research, Sudoko, Rogo, and Puzzles" * http://mat.tepper.cmu.edu/blog/?p=1302 * * * Also see, http://www.hakank.org/or-tools/rogo2.py * though this model differs in a couple of central points * which makes it much faster: * * - it use a table ( * AllowedAssignments) with the valid connections * - instead of two coordinates arrays, it use a single path array * */ private static void Solve() { Solver solver = new Solver("Rogo2"); Console.WriteLine("\n"); Console.WriteLine("**********************************************"); Console.WriteLine(" {0}", problem_name); Console.WriteLine("**********************************************\n"); // // Data // int B = -1; Console.WriteLine("Rows: {0} Cols: {1} Max Steps: {2}", rows, cols, max_steps); int[] problem_flatten = problem.Cast <int>().ToArray(); int max_point = problem_flatten.Max(); int max_sum = problem_flatten.Sum(); Console.WriteLine("max_point: {0} max_sum: {1} best: {2}", max_point, max_sum, best); IEnumerable <int> STEPS = Enumerable.Range(0, max_steps); IEnumerable <int> STEPS1 = Enumerable.Range(0, max_steps - 1); // the valid connections, to be used with AllowedAssignments IntTupleSet valid_connections = ValidConnections(rows, cols); // // Decision variables // IntVar[] path = solver.MakeIntVarArray(max_steps, 0, rows * cols - 1, "path"); IntVar[] points = solver.MakeIntVarArray(max_steps, 0, best, "points"); IntVar sum_points = points.Sum().VarWithName("sum_points"); // // Constraints // foreach (int s in STEPS) { // calculate the points (to maximize) solver.Add(points[s] == problem_flatten.Element(path[s])); // ensure that there are no black cells in // the path solver.Add(problem_flatten.Element(path[s]) != B); } solver.Add(path.AllDifferent()); // valid connections foreach (int s in STEPS1) { solver.Add(new IntVar[] { path[s], path[s + 1] }.AllowedAssignments(valid_connections)); } // around the corner solver.Add(new IntVar[] { path[max_steps - 1], path[0] }.AllowedAssignments(valid_connections)); // Symmetry breaking for (int s = 1; s < max_steps; s++) { solver.Add(path[0] < path[s]); } // // Objective // OptimizeVar obj = sum_points.Maximize(1); // // Search // DecisionBuilder db = solver.MakePhase(path, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine("sum_points: {0}", sum_points.Value()); Console.Write("path: "); foreach (int s in STEPS) { Console.Write("{0} ", path[s].Value()); } Console.WriteLine(); Console.WriteLine("(Adding 1 to coords...)"); int[,] sol = new int[rows, cols]; foreach (int s in STEPS) { int p = (int)path[s].Value(); int x = (int)(p / cols); int y = (int)(p % cols); Console.WriteLine("{0,2},{1,2} ({2} points)", x + 1, y + 1, points[s].Value()); sol[x, y] = 1; } Console.WriteLine("\nThe path is marked by 'X's:"); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { String p = sol[i, j] == 1 ? "X" : " "; String q = problem[i, j] == B ? "B" : problem[i, j] == 0 ? "." : problem[i, j].ToString(); Console.Write("{0,2}{1} ", q, p); } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Simple regular expression. * * My last name (Kjellerstrand) is quite often misspelled * in ways that this regular expression shows: * k(je|ä)ll(er|ar)?(st|b)r?an?d * * This model generates all the words that can be construed * by this regular expression. * * * Also see http://www.hakank.org/or-tools/regex.py * */ private static void Solve(int n, List <String> res) { Solver solver = new Solver("RegexGeneration"); Console.WriteLine("\nn: {0}", n); // The DFS (for regular) int n_states = 11; int input_max = 12; int initial_state = 1; // 0 is for the failing state int[] accepting_states = { 12 }; // The DFA int[,] transition_fn = { // 1 2 3 4 5 6 7 8 9 0 1 2 // { 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 1 k { 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0 }, // 2 je { 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0 }, // 3 ä { 0, 0, 0, 0, 5, 6, 7, 8, 0, 0, 0, 0 }, // 4 ll { 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0 }, // 5 er { 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0 }, // 6 ar { 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0 }, // 7 st { 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0 }, // 8 b { 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0 }, // 9 r { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12 }, // 10 a { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12 }, // 11 n // 12 d }; // Name of the states String[] s = { "k", "je", "ä", "ll", "er", "ar", "st", "b", "r", "a", "n", "d" }; // // Decision variables // IntVar[] x = solver.MakeIntVarArray(n, 1, input_max, "x"); // // Constraints // MyRegular(solver, x, n_states, input_max, transition_fn, initial_state, accepting_states); // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db); while (solver.NextSolution()) { List <String> res2 = new List <String>(); // State 1 (the start state) is not included in the // state array (x) so we add it first. res2.Add(s[0]); for (int i = 0; i < n; i++) { res2.Add(s[x[i].Value() - 1]); } res.Add(String.Join("", res2.ToArray())); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Solves the N-Queens problem. * * Syntax: nqueens.exe n num print * where * n : size of board * num : number of solutions to calculate * print: print the results (if > 0) * */ private static void Solve(int n = 8, int num = 0, int print = 1) { Solver solver = new Solver("N-Queens"); // // Decision variables // IntVar[] q = solver.MakeIntVarArray(n, 0, n - 1, "q"); // // Constraints // solver.Add(q.AllDifferent()); IntVar[] q1 = new IntVar[n]; IntVar[] q2 = new IntVar[n]; for (int i = 0; i < n; i++) { q1[i] = (q[i] + i).Var(); q2[i] = (q[i] - i).Var(); } solver.Add(q1.AllDifferent()); solver.Add(q2.AllDifferent()); // Alternative version: it works as well but are not that clear /* * solver.Add((from i in Enumerable.Range(0, n) * select (q[i] + i).Var()).ToArray().AllDifferent()); * * solver.Add((from i in Enumerable.Range(0, n) * select (q[i] - i).Var()).ToArray().AllDifferent()); */ // // Search // DecisionBuilder db = solver.MakePhase(q, Solver.CHOOSE_MIN_SIZE_LOWEST_MAX, Solver.ASSIGN_CENTER_VALUE); solver.NewSearch(db); int c = 0; while (solver.NextSolution()) { if (print > 0) { for (int i = 0; i < n; i++) { Console.Write("{0} ", q[i].Value()); } Console.WriteLine(); } c++; if (num > 0 && c >= num) { break; } } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Sicherman Dice. * * From http://en.wikipedia.org/wiki/Sicherman_dice * "" * Sicherman dice are the only pair of 6-sided dice which are not normal dice, * bear only positive integers, and have the same probability distribution for * the sum as normal dice. * * The faces on the dice are numbered 1, 2, 2, 3, 3, 4 and 1, 3, 4, 5, 6, 8. * "" * * I read about this problem in a book/column by Martin Gardner long * time ago, and got inspired to model it now by the WolframBlog post * "Sicherman Dice": http://blog.wolfram.com/2010/07/13/sicherman-dice/ * * This model gets the two different ways, first the standard way and * then the Sicherman dice: * * x1 = [1, 2, 3, 4, 5, 6] * x2 = [1, 2, 3, 4, 5, 6] * ---------- * x1 = [1, 2, 2, 3, 3, 4] * x2 = [1, 3, 4, 5, 6, 8] * * * Extra: If we also allow 0 (zero) as a valid value then the * following two solutions are also valid: * * x1 = [0, 1, 1, 2, 2, 3] * x2 = [2, 4, 5, 6, 7, 9] * ---------- * x1 = [0, 1, 2, 3, 4, 5] * x2 = [2, 3, 4, 5, 6, 7] * * These two extra cases are mentioned here: * http://mathworld.wolfram.com/SichermanDice.html * * * Also see http://www.hakank.org/or-tools/sicherman_dice.py * */ private static void Solve() { Solver solver = new Solver("SichermanDice"); // // Data // int n = 6; int m = 10; int lowest_value = 0; // standard distribution int[] standard_dist = { 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 }; IEnumerable <int> RANGE = Enumerable.Range(0, n); IEnumerable <int> RANGE1 = Enumerable.Range(0, n - 1); // // Decision variables // IntVar[] x1 = solver.MakeIntVarArray(n, lowest_value, m, "x1"); IntVar[] x2 = solver.MakeIntVarArray(n, lowest_value, m, "x2"); // // Constraints // for (int k = 0; k < standard_dist.Length; k++) { solver.Add((from i in RANGE from j in RANGE select x1[i] + x2[j] == k + 2 ).ToArray().Sum() == standard_dist[k]); } // symmetry breaking foreach (int i in RANGE1) { solver.Add(x1[i] <= x1[i + 1]); solver.Add(x2[i] <= x2[i + 1]); solver.Add(x1[i] <= x2[i]); } // // Search // DecisionBuilder db = solver.MakePhase(x1.Concat(x2).ToArray(), Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db); while (solver.NextSolution()) { Console.Write("x1: "); foreach (int i in RANGE) { Console.Write(x1[i].Value() + " "); } Console.Write("\nx2: "); foreach (int i in RANGE) { Console.Write(x2[i].Value() + " "); } Console.WriteLine("\n"); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Secret Santa problem in Google CP Solver. * * From Ruby Quiz Secret Santa * http://www.rubyquiz.com/quiz2.html * """ * Honoring a long standing tradition started by my wife's dad, my friends * all play a Secret Santa game around Christmas time. We draw names and * spend a week sneaking that person gifts and clues to our identity. On the * last night of the game, we get together, have dinner, share stories, and, * most importantly, try to guess who our Secret Santa was. It's a crazily * fun way to enjoy each other's company during the holidays. * * To choose Santas, we use to draw names out of a hat. This system was * tedious, prone to many 'Wait, I got myself...' problems. This year, we * made a change to the rules that further complicated picking and we knew * the hat draw would not stand up to the challenge. Naturally, to solve * this problem, I scripted the process. Since that turned out to be more * interesting than I had expected, I decided to share. * * This weeks Ruby Quiz is to implement a Secret Santa selection script. * * Your script will be fed a list of names on STDIN. * ... * Your script should then choose a Secret Santa for every name in the list. * Obviously, a person cannot be their own Secret Santa. In addition, my friends * no longer allow people in the same family to be Santas for each other and your * script should take this into account. * """ * * Comment: This model skips the file input and mail parts. We * assume that the friends are identified with a number from 1..n, * and the families is identified with a number 1..num_families. * * Also see http://www.hakank.org/or-tools/secret_santa.py * Also see http://www.hakank.org/or-tools/secret_santa2.cs * */ private static void Solve() { Solver solver = new Solver("SecretSanta"); int[] family = { 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 4, 4 }; int n = family.Length; Console.WriteLine("n = {0}", n); IEnumerable <int> RANGE = Enumerable.Range(0, n); // // Decision variables // IntVar[] x = solver.MakeIntVarArray(n, 0, n - 1, "x"); // // Constraints // solver.Add(x.AllDifferent()); // Can't be one own"s Secret Santa // (i.e. ensure that there are no fix-point in the array.) foreach (int i in RANGE) { solver.Add(x[i] != i); } // No Secret Santa to a person in the same family foreach (int i in RANGE) { solver.Add(solver.MakeIntConst(family[i]) != family.Element(x[i])); } // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.INT_VAR_SIMPLE, Solver.INT_VALUE_SIMPLE); solver.NewSearch(db); while (solver.NextSolution()) { Console.Write("x: "); foreach (int i in RANGE) { Console.Write(x[i].Value() + " "); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Eq 10 in Google CP Solver. * * Standard benchmark problem. * * Also see http://hakank.org/or-tools/eq10.py * */ private static void Solve() { Solver solver = new Solver("Eq10"); int n = 7; // // Decision variables // IntVar X1 = solver.MakeIntVar(0, 10, "X1"); IntVar X2 = solver.MakeIntVar(0, 10, "X2"); IntVar X3 = solver.MakeIntVar(0, 10, "X3"); IntVar X4 = solver.MakeIntVar(0, 10, "X4"); IntVar X5 = solver.MakeIntVar(0, 10, "X5"); IntVar X6 = solver.MakeIntVar(0, 10, "X6"); IntVar X7 = solver.MakeIntVar(0, 10, "X7"); IntVar[] X = { X1, X2, X3, X4, X5, X6, X7 }; // // Constraints // solver.Add(0 + 98527 * X1 + 34588 * X2 + 5872 * X3 + 59422 * X5 + 65159 * X7 == 1547604 + 30704 * X4 + 29649 * X6); solver.Add(0 + 98957 * X2 + 83634 * X3 + 69966 * X4 + 62038 * X5 + 37164 * X6 + 85413 * X7 == 1823553 + 93989 * X1); solver.Add(900032 + 10949 * X1 + 77761 * X2 + 67052 * X5 == 0 + 80197 * X3 + 61944 * X4 + 92964 * X6 + 44550 * X7); solver.Add(0 + 73947 * X1 + 84391 * X3 + 81310 * X5 == 1164380 + 96253 * X2 + 44247 * X4 + 70582 * X6 + 33054 * X7); solver.Add(0 + 13057 * X3 + 42253 * X4 + 77527 * X5 + 96552 * X7 == 1185471 + 60152 * X1 + 21103 * X2 + 97932 * X6); solver.Add(1394152 + 66920 * X1 + 55679 * X4 == 0 + 64234 * X2 + 65337 * X3 + 45581 * X5 + 67707 * X6 + 98038 * X7); solver.Add(0 + 68550 * X1 + 27886 * X2 + 31716 * X3 + 73597 * X4 + 38835 * X7 == 279091 + 88963 * X5 + 76391 * X6); solver.Add(0 + 76132 * X2 + 71860 * X3 + 22770 * X4 + 68211 * X5 + 78587 * X6 == 480923 + 48224 * X1 + 82817 * X7); solver.Add(519878 + 94198 * X2 + 87234 * X3 + 37498 * X4 == 0 + 71583 * X1 + 25728 * X5 + 25495 * X6 + 70023 * X7); solver.Add(361921 + 78693 * X1 + 38592 * X5 + 38478 * X6 == 0 + 94129 * X2 + 43188 * X3 + 82528 * X4 + 69025 * X7); // // Search // DecisionBuilder db = solver.MakePhase(X, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db); while (solver.NextSolution()) { for (int i = 0; i < n; i++) { Console.Write(X[i].ToString() + " "); } Console.WriteLine(); } Console.WriteLine("\nSolutions: " + solver.Solutions()); Console.WriteLine("WallTime: " + solver.WallTime() + "ms "); Console.WriteLine("Failures: " + solver.Failures()); Console.WriteLine("Branches: " + solver.Branches()); solver.EndSearch(); }
/** * * Max flow problem. * * From Winston 'Operations Research', page 420f, 423f * Sunco Oil example. * * * Also see http://www.hakank.org/or-tools/max_flow_winston1.py * */ private static void Solve() { Solver solver = new Solver("MaxFlowWinston1"); // // Data // int n = 5; IEnumerable <int> NODES = Enumerable.Range(0, n); // The arcs // Note: // This is 1-based to be compatible with other implementations. // int[,] arcs1 = { { 1, 2 }, { 1, 3 }, { 2, 3 }, { 2, 4 }, { 3, 5 }, { 4, 5 }, { 5, 1 } }; // Capacities int [] cap = { 2, 3, 3, 4, 2, 1, 100 }; // Convert arcs to 0-based int num_arcs = arcs1.GetLength(0); IEnumerable <int> ARCS = Enumerable.Range(0, num_arcs); int[,] arcs = new int[num_arcs, 2]; foreach (int i in ARCS) { for (int j = 0; j < 2; j++) { arcs[i, j] = arcs1[i, j] - 1; } } // Convert arcs to matrix (for sanity checking below) int[,] mat = new int[num_arcs, num_arcs]; foreach (int i in NODES) { foreach (int j in NODES) { int c = 0; foreach (int k in ARCS) { if (arcs[k, 0] == i && arcs[k, 1] == j) { c = 1; } } mat[i, j] = c; } } // // Decision variables // IntVar[,] flow = solver.MakeIntVarMatrix(n, n, 0, 200, "flow"); IntVar z = flow[n - 1, 0].VarWithName("z"); // // Constraints // // capacity of arcs foreach (int i in ARCS) { solver.Add(flow[arcs[i, 0], arcs[i, 1]] <= cap[i]); } // inflows == outflows foreach (int i in NODES) { var s1 = (from k in ARCS where arcs[k, 1] == i select flow[arcs[k, 0], arcs[k, 1]] ).ToArray().Sum(); var s2 = (from k in ARCS where arcs[k, 0] == i select flow[arcs[k, 0], arcs[k, 1]] ).ToArray().Sum(); solver.Add(s1 == s2); } // Sanity check: just arcs with connections can have a flow. foreach (int i in NODES) { foreach (int j in NODES) { if (mat[i, j] == 0) { solver.Add(flow[i, j] == 0); } } } // // Objective // OptimizeVar obj = z.Maximize(1); // // Search // DecisionBuilder db = solver.MakePhase(flow.Flatten(), Solver.INT_VAR_DEFAULT, Solver.ASSIGN_MAX_VALUE); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine("z: {0}", z.Value()); foreach (int i in NODES) { foreach (int j in NODES) { Console.Write(flow[i, j].Value() + " "); } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * This model was inspired by David Curran's * blog post "The Fairest Way to Pick a Team " * http://liveatthewitchtrials.blogspot.se/2012/06/fairest-way-to-pick-team.html * """ * What is the best way to pick a team? As kids we would always strictly alternate * between teams so team 1 had first team 2 the second pick and then team 1 again etc. * * Most things you can measure about people are on a bell curve. A small number of * people are bad, most are in the middle and a few are good. There are a few good * known metrics of ability. None are perfect, there is no one number that can sum up * ability. The simpler the sport the more one metric can tell you, in cycling VO2 max is * a very good indicator. Whereas in soccer VO2 max, kicking speed, vertical leap, number * of keep me ups you can do etc could all measure some part of football ability. * * So say there was one good metric for a task and teams were picked based on this. * Is the standard strict alteration, where Team 1 picks then Team 2 alternating, fair? * Fair here meaning both teams end up with a similar quality. * """ * * This version has two changes compared to http://www.hakank.org/or-tools/picking_teams.cs * - there can be more than 2 teams * - it don't have to be exactly the same number of members in each team * * * Model by Hakan Kjellerstrand ([email protected]) * * See other or-tools/C# models at http://www.hakank.org/or-tools/#csharp * */ private static void Solve(int n = 10, int num_teams = 2, int team_diff = 1, int max = 10, int sols_to_show = 0) { Solver solver = new Solver("PickingTeams"); Console.WriteLine("n : " + n); Console.WriteLine("num_teams: " + num_teams); // New Console.WriteLine("team_diff: " + team_diff); // New Console.WriteLine("max : " + max); Console.WriteLine("sols_to_show: " + sols_to_show); // New: We skip this check // if (n % num_teams != 0) { // Console.WriteLine("The number of people (n) must be divisible by 2."); // System.Environment.Exit(1); // } // // Data // // Randomize data: int seed = (int)DateTime.Now.Ticks; Random generator = new Random(seed); int[] s = new int[n]; for (int i = 0; i < n; i++) { s[i] = 1 + generator.Next(max); if (n <= 100) { Console.Write(s[i] + " "); } } Console.WriteLine(); Console.WriteLine("\n" + n + " numbers generated\n"); int the_sum = s.Sum(); int half_sum = (int)the_sum / num_teams; Console.WriteLine("sum: " + the_sum + " half_sum: " + half_sum); IEnumerable <int> NRange = Enumerable.Range(0, n); // // Decision variables // // To which team (s) do x[i] belong? // New: Added num_teams-1 IntVar[] x = solver.MakeIntVarArray(n, 0, num_teams - 1, "x"); // The old version for 2 teams // IntVar diff = ( // (from k in NRange select (s[k]*(x[k] == 0)) ).ToArray().Sum() - // (from k in NRange select (s[k]*(x[k] == 1)) ).ToArray().Sum() // ).Abs().Var(); // New: // Calculate the team sums // Note: It is more efficient to restrict lower and upper bounds of the team sums. // Here I arbitrarily allow a slack of // sum +/- (half_sum/num_teams) // For specific applications this might be adjusted. int n3 = half_sum / num_teams; Console.WriteLine("n3: " + n3); Console.WriteLine("half_sum-n3 " + (half_sum - n3) + "... half_sum+n3: " + (half_sum + n3)); IntVar[] team_sum = solver.MakeIntVarArray(num_teams, half_sum - n3, half_sum + n3, "team_sum"); for (int team = 0; team < num_teams; team++) { team_sum[team] = (from k in NRange select(s[k] * (x[k] == team))).ToArray().Sum().Var(); } // New: // Calculate the total number of difference points between the // teams (to be minimized) IntVar diff = (from t1 in Enumerable.Range(0, num_teams) from t2 in Enumerable.Range(0, num_teams) where t1 < t2 select(team_sum[t1] - team_sum[t2]).Abs().Var()).ToArray().Sum().Var(); Console.WriteLine("diff.Max(): " + diff.Max()); // // New: Number of members in each team // // Note that we restrict the possible values to +/- team_diff. int n2 = (int)n / num_teams; Console.WriteLine("n2: " + n2); IntVar[] team_num = solver.MakeIntVarArray(num_teams, n2 - team_diff, n2 + team_diff, "team_num"); for (int team = 0; team < num_teams; team++) { team_num[team] = (from k in NRange select(x[k] == team)).ToArray().Sum().Var(); } // New: We send all the IntVar arrays to the solver IntVar[] all = x.Concat(team_sum).Concat(team_num).ToArray(); // // Constraints // // New: Ensure that there are the (about) same number of people in each team. for (int t = 0; t < num_teams; t++) { solver.Add((((from k in NRange select(x[k] == t)).ToArray().Sum() - n2)).Abs() <= team_diff); } // The teams_sums should add up to the total sum solver.Add(team_sum.Sum() == the_sum); // symmetry breaking: assign first member to team 0 solver.Add(x[0] == 0); // Odd sum must yield odd diff, even sum yield even diff IntVar even_odd = solver.MakeIntConst(the_sum % 2); solver.Add(solver.MakeModuloConstraint(diff, 2, even_odd)); // // Search // DecisionBuilder db = solver.MakePhase(all, // Solver.INT_VAR_DEFAULT, // Solver.INT_VAR_SIMPLE, // Solver.CHOOSE_FIRST_UNBOUND, // Solver.CHOOSE_RANDOM, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, // Solver.CHOOSE_MIN_SIZE_HIGHEST_MIN, // Solver.CHOOSE_MIN_SIZE_LOWEST_MAX, // Solver.CHOOSE_MIN_SIZE_HIGHEST_MAX, // Solver.CHOOSE_PATH, // Solver.INT_VALUE_DEFAULT // Solver.INT_VALUE_SIMPLE // Solver.ASSIGN_MIN_VALUE // Solver.ASSIGN_MAX_VALUE Solver.ASSIGN_RANDOM_VALUE // Solver.ASSIGN_CENTER_VALUE ); /* * DefaultPhaseParameters parameters = new DefaultPhaseParameters(); * * parameters.heuristic_period = 20; * // parameters.heuristic_period = 10; * * // parameters.heuristic_num_failures_limit = 1000; * // parameters.restart_log_size = -1; * // parameters.restart_log_size = 100; * // parameters.run_all_heuristics = false; * * // parameters.var_selection_schema = DefaultPhaseParameters.CHOOSE_MAX_SUM_IMPACT; * // parameters.var_selection_schema = DefaultPhaseParameters.CHOOSE_MAX_AVERAGE_IMPACT ; * parameters.var_selection_schema = DefaultPhaseParameters.CHOOSE_MAX_VALUE_IMPACT; * * // parameters.value_selection_schema = DefaultPhaseParameters.SELECT_MIN_IMPACT; * parameters.value_selection_schema = DefaultPhaseParameters.SELECT_MAX_IMPACT; * * parameters.initialization_splits = 10; * // parameters.initialization_splits = 20; * // parameters.initialization_splits = n; * * // parameters.random_seed = 0; * * DecisionBuilder db = solver.MakeDefaultPhase(all, parameters); */ OptimizeVar opt = diff.Minimize(1); solver.NewSearch(db, opt); int sols = 0; while (solver.NextSolution()) { sols++; Console.WriteLine("\n\nDiff: " + diff.Value()); if (n <= 10000) { Console.WriteLine("Assignment: "); long[] assignments = new long[n]; foreach (int i in NRange) { Console.Write(x[i].Value() + " "); assignments[i] = x[i].Value(); } Console.WriteLine(); for (int team = 0; team < num_teams; team++) { Console.Write("team " + team + ": "); foreach (int i in NRange) { if (assignments[i] == team) { Console.Write((i) + " "); } } Console.WriteLine(); } } Console.Write("Sum of each team : "); for (int t = 0; t < num_teams; t++) { Console.Write(team_sum[t].Value() + " "); } Console.WriteLine(); Console.Write("Number of members in each team: "); for (int t = 0; t < num_teams; t++) { Console.Write(team_num[t].Value() + " "); } Console.WriteLine(); if (sols_to_show > 0 && sols >= sols_to_show) { break; } } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Moving furnitures (scheduling) problem in Google CP Solver. * * Marriott & Stukey: 'Programming with constraints', page 112f * * The model implements an decomposition of the global constraint * cumulative (see above). * * Also see http://www.hakank.org/or-tools/furniture_moving.py * */ private static void Solve() { Solver solver = new Solver("FurnitureMoving"); int n = 4; int[] duration = { 30, 10, 15, 15 }; int[] demand = { 3, 1, 3, 2 }; int upper_limit = 160; // // Decision variables // IntVar[] start_times = solver.MakeIntVarArray(n, 0, upper_limit, "start_times"); IntVar[] end_times = solver.MakeIntVarArray(n, 0, upper_limit * 2, "end_times"); IntVar end_time = solver.MakeIntVar(0, upper_limit * 2, "end_time"); // number of needed resources, to be minimized or constrained IntVar num_resources = solver.MakeIntVar(0, 10, "num_resources"); // // Constraints // for (int i = 0; i < n; i++) { solver.Add(end_times[i] == start_times[i] + duration[i]); } solver.Add(end_time == end_times.Max()); MyCumulative(solver, start_times, duration, demand, num_resources); // // Some extra constraints to play with // // all tasks must end within an hour // solver.Add(end_time <= 60); // All tasks should start at time 0 // for(int i = 0; i < n; i++) { // solver.Add(start_times[i] == 0); // } // limitation of the number of people // solver.Add(num_resources <= 3); solver.Add(num_resources <= 4); // // Objective // // OptimizeVar obj = num_resources.Minimize(1); OptimizeVar obj = end_time.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(start_times, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine("num_resources: {0} end_time: {1}", num_resources.Value(), end_time.Value()); for (int i = 0; i < n; i++) { Console.WriteLine("Task {0,1}: {1,2} -> {2,2} -> {3,2} (demand: {4})", i, start_times[i].Value(), duration[i], end_times[i].Value(), demand[i]); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
public void EndSearch() { pinned_decision_builder_ = null; pinned_search_monitors_.Clear(); EndSearchAux(); }
/** * * Bus scheduling. * * Minimize number of buses in timeslots. * * Problem from Taha "Introduction to Operations Research", page 58. * * This is a slightly more general model than Taha's. * * Also see, http://www.hakank.org/or-tools/bus_schedule.py * */ private static long Solve(long num_buses_check = 0) { Solver solver = new Solver("BusSchedule"); // // data // int time_slots = 6; int[] demands = { 8, 10, 7, 12, 4, 4 }; int max_num = demands.Sum(); // // Decision variables // // How many buses start the schedule at time slot t IntVar[] x = solver.MakeIntVarArray(time_slots, 0, max_num, "x"); // Total number of buses IntVar num_buses = x.Sum().VarWithName("num_buses"); // // Constraints // // Meet the demands for this and the next time slot. for (int i = 0; i < time_slots - 1; i++) { solver.Add(x[i] + x[i + 1] >= demands[i]); } // The demand "around the clock" solver.Add(x[time_slots - 1] + x[0] - demands[time_slots - 1] == 0); // For showing all solutions of minimal number of buses if (num_buses_check > 0) { solver.Add(num_buses == num_buses_check); } // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); if (num_buses_check == 0) { // Minimize num_buses OptimizeVar obj = num_buses.Minimize(1); solver.NewSearch(db, obj); } else { solver.NewSearch(db); } long result = 0; while (solver.NextSolution()) { result = num_buses.Value(); Console.Write("x: "); for (int i = 0; i < time_slots; i++) { Console.Write("{0,2} ", x[i].Value()); } Console.WriteLine("num_buses: " + num_buses.Value()); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); return(result); }
/** * * Nurse rostering * * This is a simple nurse rostering model using a DFA and * my decomposition of regular constraint. * * The DFA is from MiniZinc Tutorial, Nurse Rostering example: * - one day off every 4 days * - no 3 nights in a row. * * Also see http://www.hakank.org/or-tools/nurse_rostering.py * */ private static void Solve() { Solver solver = new Solver("NurseRostering"); // // Data // // Note: If you change num_nurses or num_days, // please also change the constraints // on nurse_stat and/or day_stat. int num_nurses = 7; int num_days = 14; // Note: I had to add a dummy shift. int dummy_shift = 0; int day_shift = 1; int night_shift = 2; int off_shift = 3; int[] shifts = { dummy_shift, day_shift, night_shift, off_shift }; int[] valid_shifts = { day_shift, night_shift, off_shift }; // the DFA (for regular) int n_states = 6; int input_max = 3; int initial_state = 1; // 0 is for the failing state int[] accepting_states = { 1, 2, 3, 4, 5, 6 }; int[,] transition_fn = { // d,n,o { 2, 3, 1 }, // state 1 { 4, 4, 1 }, // state 2 { 4, 5, 1 }, // state 3 { 6, 6, 1 }, // state 4 { 6, 0, 1 }, // state 5 { 0, 0, 1 } // state 6 }; string[] days = { "d", "n", "o" }; // for presentation // // Decision variables // // For regular IntVar[,] x = solver.MakeIntVarMatrix(num_nurses, num_days, valid_shifts, "x"); IntVar[] x_flat = x.Flatten(); // summary of the nurses IntVar[] nurse_stat = solver.MakeIntVarArray(num_nurses, 0, num_days, "nurse_stat"); // summary of the shifts per day int num_shifts = shifts.Length; IntVar[,] day_stat = new IntVar[num_days, num_shifts]; for (int i = 0; i < num_days; i++) { for (int j = 0; j < num_shifts; j++) { day_stat[i, j] = solver.MakeIntVar(0, num_nurses, "day_stat"); } } // // Constraints // for (int i = 0; i < num_nurses; i++) { IntVar[] reg_input = new IntVar[num_days]; for (int j = 0; j < num_days; j++) { reg_input[j] = x[i, j]; } MyRegular(solver, reg_input, n_states, input_max, transition_fn, initial_state, accepting_states); } // // Statistics and constraints for each nurse // for (int i = 0; i < num_nurses; i++) { // Number of worked days (either day or night shift) IntVar[] b = new IntVar[num_days]; for (int j = 0; j < num_days; j++) { b[j] = ((x[i, j] == day_shift) + (x[i, j] == night_shift)).Var(); } solver.Add(b.Sum() == nurse_stat[i]); // Each nurse must work between 7 and 10 // days/nights during this period solver.Add(nurse_stat[i] >= 7); solver.Add(nurse_stat[i] <= 10); } // // Statistics and constraints for each day // for (int j = 0; j < num_days; j++) { for (int t = 0; t < num_shifts; t++) { IntVar[] b = new IntVar[num_nurses]; for (int i = 0; i < num_nurses; i++) { b[i] = x[i, j] == t; } solver.Add(b.Sum() == day_stat[j, t]); } // // Some constraints for each day: // // Note: We have a strict requirements of // the number of shifts. // Using atleast constraints is harder // in this model. // if (j % 7 == 5 || j % 7 == 6) { // special constraints for the weekends solver.Add(day_stat[j, day_shift] == 2); solver.Add(day_stat[j, night_shift] == 1); solver.Add(day_stat[j, off_shift] == 4); } else { // for workdays: // - exactly 3 on day shift solver.Add(day_stat[j, day_shift] == 3); // - exactly 2 on night solver.Add(day_stat[j, night_shift] == 2); // - exactly 2 off duty solver.Add(day_stat[j, off_shift] == 2); } } // // Search // DecisionBuilder db = solver.MakePhase(x_flat, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db); int num_solutions = 0; while (solver.NextSolution()) { num_solutions++; for (int i = 0; i < num_nurses; i++) { Console.Write("Nurse #{0,-2}: ", i); var occ = new Dictionary <int, int>(); for (int j = 0; j < num_days; j++) { int v = (int)x[i, j].Value() - 1; if (!occ.ContainsKey(v)) { occ[v] = 0; } occ[v]++; Console.Write(days[v] + " "); } Console.Write(" #workdays: {0,2}", nurse_stat[i].Value()); foreach (int s in valid_shifts) { int v = 0; if (occ.ContainsKey(s - 1)) { v = occ[s - 1]; } Console.Write(" {0}:{1}", days[s - 1], v); } Console.WriteLine(); } Console.WriteLine(); Console.WriteLine("Statistics per day:\nDay d n o"); for (int j = 0; j < num_days; j++) { Console.Write("Day #{0,2}: ", j); foreach (int t in valid_shifts) { Console.Write(day_stat[j, t].Value() + " "); } Console.WriteLine(); } Console.WriteLine(); // We just show 2 solutions if (num_solutions > 1) { break; } } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
public void NewSearch(DecisionBuilder db, SearchMonitor sm1, SearchMonitor sm2, SearchMonitor sm3, SearchMonitor sm4) { pinned_decision_builder_ = db; pinned_search_monitors_.Clear(); pinned_search_monitors_.Add(sm1); pinned_search_monitors_.Add(sm2); pinned_search_monitors_.Add(sm3); pinned_search_monitors_.Add(sm4); NewSearchAux(db, sm1, sm2, sm3, sm4); }
/** * * Set partition problem. * * Problem formulation from * http://www.koalog.com/resources/samples/PartitionProblem.java.html * """ * This is a partition problem. * Given the set S = {1, 2, ..., n}, * it consists in finding two sets A and B such that: * * A U B = S, * |A| = |B|, * sum(A) = sum(B), * sum_squares(A) = sum_squares(B) * * """ * * This model uses a binary matrix to represent the sets. * * * Also see http://www.hakank.org/or-tools/set_partition.py * */ private static void Solve(int n = 16, int num_sets = 2) { Solver solver = new Solver("SetPartition"); Console.WriteLine("n: {0}", n); Console.WriteLine("num_sets: {0}", num_sets); IEnumerable <int> Sets = Enumerable.Range(0, num_sets); IEnumerable <int> NRange = Enumerable.Range(0, n); // // Decision variables // IntVar[,] a = solver.MakeIntVarMatrix(num_sets, n, 0, 1, "a"); IntVar[] a_flat = a.Flatten(); // // Constraints // // partition set partition_sets(solver, a, num_sets, n); foreach (int i in Sets) { foreach (int j in Sets) { // same cardinality solver.Add((from k in NRange select a[i, k]).ToArray().Sum() == (from k in NRange select a[j, k]).ToArray().Sum()); // same sum solver.Add((from k in NRange select(k * a[i, k])).ToArray().Sum() == (from k in NRange select(k * a[j, k])).ToArray().Sum()); // same sum squared solver.Add((from k in NRange select(k * a[i, k] * k * a[i, k])).ToArray().Sum() == (from k in NRange select(k * a[j, k] * k * a[j, k])).ToArray().Sum()); } } // symmetry breaking for num_sets == 2 if (num_sets == 2) { solver.Add(a[0, 0] == 1); } // // Search // DecisionBuilder db = solver.MakePhase(a_flat, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db); while (solver.NextSolution()) { int[,] a_val = new int[num_sets, n]; foreach (int i in Sets) { foreach (int j in NRange) { a_val[i, j] = (int)a[i, j].Value(); } } Console.WriteLine("sums: {0}", (from j in NRange select(j + 1) * a_val[0, j]).ToArray().Sum()); Console.WriteLine( "sums squared: {0}", (from j in NRange select(int) Math.Pow((j + 1) * a_val[0, j], 2)).ToArray().Sum()); // Show the numbers in each set foreach (int i in Sets) { if ((from j in NRange select a_val[i, j]).ToArray().Sum() > 0) { Console.Write(i + 1 + ": "); foreach (int j in NRange) { if (a_val[i, j] == 1) { Console.Write((j + 1) + " "); } } Console.WriteLine(); } } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Secret Santa problem II in Google CP Solver. * * From Maple Primes: 'Secret Santa Graph Theory' * http://www.mapleprimes.com/blog/jpmay/secretsantagraphtheory * """ * Every year my extended family does a 'secret santa' gift exchange. * Each person draws another person at random and then gets a gift for * them. At first, none of my siblings were married, and so the draw was * completely random. Then, as people got married, we added the restriction * that spouses should not draw each others names. This restriction meant * that we moved from using slips of paper on a hat to using a simple * computer program to choose names. Then people began to complain when * they would get the same person two years in a row, so the program was * modified to keep some history and avoid giving anyone a name in their * recent history. This year, not everyone was participating, and so after * removing names, and limiting the number of exclusions to four per person, * I had data something like this: * * Name: Spouse, Recent Picks * * Noah: Ava. Ella, Evan, Ryan, John * Ava: Noah, Evan, Mia, John, Ryan * Ryan: Mia, Ella, Ava, Lily, Evan * Mia: Ryan, Ava, Ella, Lily, Evan * Ella: John, Lily, Evan, Mia, Ava * John: Ella, Noah, Lily, Ryan, Ava * Lily: Evan, John, Mia, Ava, Ella * Evan: Lily, Mia, John, Ryan, Noah * """ * * Note: I interpret this as the following three constraints: * 1) One cannot be a Secret Santa of one's spouse * 2) One cannot be a Secret Santa for somebody two years in a row * 3) Optimization: maximize the time since the last time * * This model also handle single persons, something the original * problem don't mention. * * * Also see http://www.hakank.org/or-tools/secret_santa2.py * */ private static void Solve(int single = 0) { Solver solver = new Solver("SecretSanta2"); Console.WriteLine("\nSingle: {0}", single); // // The matrix version of earlier rounds. // M means that no earlier Santa has been assigned. // Note: Ryan and Mia has the same recipient for years 3 and 4, // and Ella and John has for year 4. // This seems to be caused by modification of // original data. // int n_no_single = 8; int M = n_no_single + 1; int[][] rounds_no_single = { // N A R M El J L Ev new int[] { 0, M, 3, M, 1, 4, M, 2 }, // Noah new int[] { M, 0, 4, 2, M, 3, M, 1 }, // Ava new int[] { M, 2, 0, M, 1, M, 3, 4 }, // Ryan new int[] { M, 1, M, 0, 2, M, 3, 4 }, // Mia new int[] { M, 4, M, 3, 0, M, 1, 2 }, // Ella new int[] { 1, 4, 3, M, M, 0, 2, M }, // John new int[] { M, 3, M, 2, 4, 1, 0, M }, // Lily new int[] { 4, M, 3, 1, M, 2, M, 0 } // Evan }; // // Rounds with a single person (fake data) // int n_with_single = 9; M = n_with_single + 1; int[][] rounds_single = { // N A R M El J L Ev S new int[] { 0, M, 3, M, 1, 4, M, 2, 2 }, // Noah new int[] { M, 0, 4, 2, M, 3, M, 1, 1 }, // Ava new int[] { M, 2, 0, M, 1, M, 3, 4, 4 }, // Ryan new int[] { M, 1, M, 0, 2, M, 3, 4, 3 }, // Mia new int[] { M, 4, M, 3, 0, M, 1, 2, M }, // Ella new int[] { 1, 4, 3, M, M, 0, 2, M, M }, // John new int[] { M, 3, M, 2, 4, 1, 0, M, M }, // Lily new int[] { 4, M, 3, 1, M, 2, M, 0, M }, // Evan new int[] { 1, 2, 3, 4, M, 2, M, M, 0 } // Single }; int Noah = 0; int Ava = 1; int Ryan = 2; int Mia = 3; int Ella = 4; int John = 5; int Lily = 6; int Evan = 7; int n = n_no_single; int[][] rounds = rounds_no_single; if (single == 1) { n = n_with_single; rounds = rounds_single; } M = n + 1; IEnumerable <int> RANGE = Enumerable.Range(0, n); String[] persons = { "Noah", "Ava", "Ryan", "Mia", "Ella", "John", "Lily", "Evan", "Single" }; int[] spouses = { Ava, // Noah Noah, // Ava Mia, // Rya Ryan, // Mia John, // Ella Ella, // John Evan, // Lily Lily, // Evan -1 // Single has no spouse }; // // Decision variables // IntVar[] santas = solver.MakeIntVarArray(n, 0, n - 1, "santas"); IntVar[] santa_distance = solver.MakeIntVarArray(n, 0, M, "santa_distance"); // total of "distance", to maximize IntVar z = santa_distance.Sum().VarWithName("z"); // // Constraints // solver.Add(santas.AllDifferent()); // Can't be one own"s Secret Santa // (i.e. ensure that there are no fix-point in the array.) foreach (int i in RANGE) { solver.Add(santas[i] != i); } // no Santa for a spouses foreach (int i in RANGE) { if (spouses[i] > -1) { solver.Add(santas[i] != spouses[i]); } } // optimize "distance" to earlier rounds: foreach (int i in RANGE) { solver.Add(santa_distance[i] == rounds[i].Element(santas[i])); } // cannot be a Secret Santa for the same person // two years in a row. foreach (int i in RANGE) { foreach (int j in RANGE) { if (rounds[i][j] == 1) { solver.Add(santas[i] != j); } } } // // Objective (minimize the distances) // OptimizeVar obj = z.Maximize(1); // // Search // DecisionBuilder db = solver.MakePhase(santas, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_CENTER_VALUE); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine("\ntotal distances: {0}", z.Value()); Console.Write("santas: "); for (int i = 0; i < n; i++) { Console.Write(santas[i].Value() + " "); } Console.WriteLine(); foreach (int i in RANGE) { Console.WriteLine("{0}\tis a Santa to {1} (distance {2})", persons[i], persons[santas[i].Value()], santa_distance[i].Value()); } } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * From "God plays dice" * "A puzzle" * http://gottwurfelt.wordpress.com/2012/02/22/a-puzzle/ * And the sequel "Answer to a puzzle" * http://gottwurfelt.wordpress.com/2012/02/24/an-answer-to-a-puzzle/ * * This problem instance was taken from the latter blog post. * (Problem 1) * * """ * 8809 = 6 * 7111 = 0 * 2172 = 0 * 6666 = 4 * 1111 = 0 * 3213 = 0 * 7662 = 2 * 9312 = 1 * 0000 = 4 * 2222 = 0 * 3333 = 0 * 5555 = 0 * 8193 = 3 * 8096 = 5 * 7777 = 0 * 9999 = 4 * 7756 = 1 * 6855 = 3 * 9881 = 5 * 5531 = 0 * * 2581 = ? * """ * * Note: * This model yields 10 solutions, since x4 is not * restricted in the constraints. * All solutions has x assigned to the correct result. * * * (Problem 2) * The problem stated in "A puzzle" * http://gottwurfelt.wordpress.com/2012/02/22/a-puzzle/ * is * """ * 8809 = 6 * 7662 = 2 * 9312 = 1 * 8193 = 3 * 8096 = 5 * 7756 = 1 * 6855 = 3 * 9881 = 5 * * 2581 = ? * """ * This problem instance yields two different solutions of x, * one is the same (correct) as for the above problem instance, * and one is not. * This is because here x0,x1,x4 and x9 are underdefined. * * */ private static void Solve(int p = 1) { Solver solver = new Solver("APuzzle"); Console.WriteLine("\nSolving p{0}", p); // // Data // int n = 10; // // Decision variables // IntVar x0 = solver.MakeIntVar(0, n - 1, "x0"); IntVar x1 = solver.MakeIntVar(0, n - 1, "x1"); IntVar x2 = solver.MakeIntVar(0, n - 1, "x2"); IntVar x3 = solver.MakeIntVar(0, n - 1, "x3"); IntVar x4 = solver.MakeIntVar(0, n - 1, "x4"); IntVar x5 = solver.MakeIntVar(0, n - 1, "x5"); IntVar x6 = solver.MakeIntVar(0, n - 1, "x6"); IntVar x7 = solver.MakeIntVar(0, n - 1, "x7"); IntVar x8 = solver.MakeIntVar(0, n - 1, "x8"); IntVar x9 = solver.MakeIntVar(0, n - 1, "x9"); IntVar[] all = { x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 }; // The unknown, i.e. 2581 = x IntVar x = solver.MakeIntVar(0, n - 1, "x"); // // Constraints // // Both problem are here shown in two // approaches: // - using equations // - using a a matrix and Sum of each row if (p == 1) { // Problem 1 solver.Add(x8 + x8 + x0 + x9 == 6); solver.Add(x7 + x1 + x1 + x1 == 0); solver.Add(x2 + x1 + x7 + x2 == 0); solver.Add(x6 + x6 + x6 + x6 == 4); solver.Add(x1 + x1 + x1 + x1 == 0); solver.Add(x3 + x2 + x1 + x3 == 0); solver.Add(x7 + x6 + x6 + x2 == 2); solver.Add(x9 + x3 + x1 + x2 == 1); solver.Add(x0 + x0 + x0 + x0 == 4); solver.Add(x2 + x2 + x2 + x2 == 0); solver.Add(x3 + x3 + x3 + x3 == 0); solver.Add(x5 + x5 + x5 + x5 == 0); solver.Add(x8 + x1 + x9 + x3 == 3); solver.Add(x8 + x0 + x9 + x6 == 5); solver.Add(x7 + x7 + x7 + x7 == 0); solver.Add(x9 + x9 + x9 + x9 == 4); solver.Add(x7 + x7 + x5 + x6 == 1); solver.Add(x6 + x8 + x5 + x5 == 3); solver.Add(x9 + x8 + x8 + x1 == 5); solver.Add(x5 + x5 + x3 + x1 == 0); // The unknown solver.Add(x2 + x5 + x8 + x1 == x); } else if (p == 2) { // Another representation of Problem 1 int[,] problem1 = { { 8, 8, 0, 9, 6 }, { 7, 1, 1, 1, 0 }, { 2, 1, 7, 2, 0 }, { 6, 6, 6, 6, 4 }, { 1, 1, 1, 1, 0 }, { 3, 2, 1, 3, 0 }, { 7, 6, 6, 2, 2 }, { 9, 3, 1, 2, 1 }, { 0, 0, 0, 0, 4 }, { 2, 2, 2, 2, 0 }, { 3, 3, 3, 3, 0 }, { 5, 5, 5, 5, 0 }, { 8, 1, 9, 3, 3 }, { 8, 0, 9, 6, 5 }, { 7, 7, 7, 7, 0 }, { 9, 9, 9, 9, 4 }, { 7, 7, 5, 6, 1 }, { 6, 8, 5, 5, 3 }, { 9, 8, 8, 1, 5 }, { 5, 5, 3, 1, 0 } }; for (int i = 0; i < problem1.GetLength(0); i++) { solver.Add((from j in Enumerable.Range(0, 4) select all[problem1[i, j]]).ToArray().Sum() == problem1[i, 4]); } solver.Add(all[2] + all[5] + all[8] + all[1] == x); } else if (p == 3) { // Problem 2 solver.Add(x8 + x8 + x0 + x9 == 6); solver.Add(x7 + x6 + x6 + x2 == 2); solver.Add(x9 + x3 + x1 + x2 == 1); solver.Add(x8 + x1 + x9 + x3 == 3); solver.Add(x8 + x0 + x9 + x6 == 5); solver.Add(x7 + x7 + x5 + x6 == 1); solver.Add(x6 + x8 + x5 + x5 == 3); solver.Add(x9 + x8 + x8 + x1 == 5); // The unknown solver.Add(x2 + x5 + x8 + x1 == x); } else { // Another representation of Problem 2 int[,] problem2 = { { 8, 8, 0, 9, 6 }, { 7, 6, 6, 2, 2 }, { 9, 3, 1, 2, 1 }, { 8, 1, 9, 3, 3 }, { 8, 0, 9, 6, 5 }, { 7, 7, 5, 6, 1 }, { 6, 8, 5, 5, 3 }, { 9, 8, 8, 1, 5 } }; for (int i = 0; i < problem2.GetLength(0); i++) { solver.Add((from j in Enumerable.Range(0, 4) select all[problem2[i, j]]).ToArray().Sum() == problem2[i, 4]); } solver.Add(all[2] + all[5] + all[8] + all[1] == x); } // // Search // DecisionBuilder db = solver.MakePhase(all, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db); while (solver.NextSolution()) { Console.Write("x: {0} x0..x9: ", x.Value()); for (int i = 0; i < n; i++) { Console.Write(all[i].Value() + " "); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Ski assignment in Google CP Solver. * * From Jeffrey Lee Hellrung, Jr.: * PIC 60, Fall 2008 Final Review, December 12, 2008 * http://www.math.ucla.edu/~jhellrun/course_files/Fall%25202008/PIC%252060%2520-%2520Data%2520Structures%2520and%2520Algorithms/final_review.pdf * """ * 5. Ski Optimization! Your job at Snapple is pleasant but in the winter * you've decided to become a ski bum. You've hooked up with the Mount * Baldy Ski Resort. They'll let you ski all winter for free in exchange * for helping their ski rental shop with an algorithm to assign skis to * skiers. Ideally, each skier should obtain a pair of skis whose height * matches his or her own height exactly. Unfortunately, this is generally * not possible. We define the disparity between a skier and his or her * skis to be the absolute value of the difference between the height of * the skier and the pair of skis. Our objective is to find an assignment * of skis to skiers that minimizes the sum of the disparities. * ... * Illustrate your algorithm by explicitly filling out the A[i, j] table * for the following sample data: * - Ski heights : 1, 2, 5, 7, 13, 21. * - Skier heights: 3, 4, 7, 11, 18. * """ * * Also see http://www.hakank.org/or-tools/ski_assignment.py * * */ private static void Solve() { Solver solver = new Solver("SkiAssignment"); // // Data // int num_skis = 6; int num_skiers = 5; int[] ski_heights = { 1, 2, 5, 7, 13, 21 }; int[] skier_heights = { 3, 4, 7, 11, 18 }; // // Decision variables // IntVar[] x = solver.MakeIntVarArray(num_skiers, 0, num_skis - 1, "x"); // // Constraints // solver.Add(x.AllDifferent()); IntVar[] z_tmp = new IntVar[num_skiers]; for (int i = 0; i < num_skiers; i++) { z_tmp[i] = (ski_heights.Element(x[i]) - skier_heights[i]).Abs().Var(); } // IntVar z = solver.MakeIntVar(0, ski_heights.Sum(), "z"); // solver.Add(z_tmp.Sum() == z); // The direct cast from IntExpr to IntVar is potentially faster than // the above code. IntVar z = z_tmp.Sum().VarWithName("z"); // // Objective // OptimizeVar obj = z.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.CHOOSE_FIRST_UNBOUND, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.Write("z: {0} x: ", z.Value()); for (int i = 0; i < num_skiers; i++) { Console.Write(x[i].Value() + " "); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Crypto problem. * * This is the standard benchmark "crypto" problem. * * From GLPK:s model cryto.mod. * * """ * This problem comes from the newsgroup rec.puzzle. * The numbers from 1 to 26 are assigned to the letters of the alphabet. * The numbers beside each word are the total of the values assigned to * the letters in the word (e.g. for LYRE: L, Y, R, E might be to equal * 5, 9, 20 and 13, or any other combination that add up to 47). * Find the value of each letter under the equations: * * BALLET 45 GLEE 66 POLKA 59 SONG 61 * CELLO 43 JAZZ 58 QUARTET 50 SOPRANO 82 * CONCERT 74 LYRE 47 SAXOPHONE 134 THEME 72 * FLUTE 30 OBOE 53 SCALE 51 VIOLIN 100 * FUGUE 50 OPERA 65 SOLO 37 WALTZ 34 * * Solution: * A, B,C, D, E,F, G, H, I, J, K,L,M, N, O, P,Q, R, S,T,U, V,W, X, Y, Z * 5,13,9,16,20,4,24,21,25,17,23,2,8,12,10,19,7,11,15,3,1,26,6,22,14,18 * * Reference: * Koalog Constraint Solver <http://www.koalog.com/php/jcs.php>, * Simple problems, the crypto-arithmetic puzzle ALPHACIPHER. * """ * * Also see http://hakank.org/or-tools/crypto.py * */ private static void Solve() { Solver solver = new Solver("Crypto"); int num_letters = 26; int BALLET = 45; int CELLO = 43; int CONCERT = 74; int FLUTE = 30; int FUGUE = 50; int GLEE = 66; int JAZZ = 58; int LYRE = 47; int OBOE = 53; int OPERA = 65; int POLKA = 59; int QUARTET = 50; int SAXOPHONE = 134; int SCALE = 51; int SOLO = 37; int SONG = 61; int SOPRANO = 82; int THEME = 72; int VIOLIN = 100; int WALTZ = 34; // // Decision variables // IntVar[] LD = solver.MakeIntVarArray(num_letters, 1, num_letters, "LD"); // Note D is not used in the constraints below IntVar A = LD[0]; IntVar B = LD[1]; IntVar C = LD[2]; // IntVar D = LD[3]; IntVar E = LD[4]; IntVar F = LD[5]; IntVar G = LD[6]; IntVar H = LD[7]; IntVar I = LD[8]; IntVar J = LD[9]; IntVar K = LD[10]; IntVar L = LD[11]; IntVar M = LD[12]; IntVar N = LD[13]; IntVar O = LD[14]; IntVar P = LD[15]; IntVar Q = LD[16]; IntVar R = LD[17]; IntVar S = LD[18]; IntVar T = LD[19]; IntVar U = LD[20]; IntVar V = LD[21]; IntVar W = LD[22]; IntVar X = LD[23]; IntVar Y = LD[24]; IntVar Z = LD[25]; // // Constraints // solver.Add(LD.AllDifferent()); solver.Add(B + A + L + L + E + T == BALLET); solver.Add(C + E + L + L + O == CELLO); solver.Add(C + O + N + C + E + R + T == CONCERT); solver.Add(F + L + U + T + E == FLUTE); solver.Add(F + U + G + U + E == FUGUE); solver.Add(G + L + E + E == GLEE); solver.Add(J + A + Z + Z == JAZZ); solver.Add(L + Y + R + E == LYRE); solver.Add(O + B + O + E == OBOE); solver.Add(O + P + E + R + A == OPERA); solver.Add(P + O + L + K + A == POLKA); solver.Add(Q + U + A + R + T + E + T == QUARTET); solver.Add(S + A + X + O + P + H + O + N + E == SAXOPHONE); solver.Add(S + C + A + L + E == SCALE); solver.Add(S + O + L + O == SOLO); solver.Add(S + O + N + G == SONG); solver.Add(S + O + P + R + A + N + O == SOPRANO); solver.Add(T + H + E + M + E == THEME); solver.Add(V + I + O + L + I + N == VIOLIN); solver.Add(W + A + L + T + Z == WALTZ); // // Search // DecisionBuilder db = solver.MakePhase(LD, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_CENTER_VALUE); solver.NewSearch(db); String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; while (solver.NextSolution()) { for (int i = 0; i < num_letters; i++) { Console.WriteLine("{0}: {1,2}", str[i], LD[i].Value()); } Console.WriteLine(); } Console.WriteLine("\nWallTime: " + solver.WallTime() + "ms "); Console.WriteLine("Failures: " + solver.Failures()); Console.WriteLine("Branches: " + solver.Branches()); solver.EndSearch(); }
/** * * * Organizing a day. * * Simple scheduling problem. * * Problem formulation from ECLiPSe: * Slides on (Finite Domain) Constraint Logic Programming, page 38f * http://eclipse-clp.org/reports/eclipse.ppt * * * Also see http://www.hakank.org/google_or_tools/organize_day.py * */ private static void Solve() { Solver solver = new Solver("OrganizeDayIntervals"); int n = 4; int work = 0; int mail = 1; int shop = 2; int bank = 3; // the valid times of the day int begin = 9; int end = 17; // tasks int[] tasks = { work, mail, shop, bank }; // durations int[] durations = { 4, 1, 2, 1 }; // Arrays for interval variables. int[] starts_max = { begin, begin, begin, begin }; int[] ends_max = { end - 4, end - 1, end - 2, end - 1 }; // task [i,0] must be finished before task [i,1] int[,] before_tasks = { { bank, shop }, { mail, work } }; // // Decision variables // IntervalVar[] intervals = solver.MakeFixedDurationIntervalVarArray(n, starts_max, ends_max, durations, false, "task"); // // Constraints // DisjunctiveConstraint disjunctive = intervals.Disjunctive("Sequence"); solver.Add(disjunctive); // specific constraints for (int t = 0; t < before_tasks.GetLength(0); t++) { int before = before_tasks[t, 0]; int after = before_tasks[t, 1]; solver.Add(intervals[after].StartsAfterEnd(intervals[before])); } solver.Add(intervals[work].StartsAfter(11)); // // Search // SequenceVar var = disjunctive.SequenceVar(); SequenceVar[] seq_array = new SequenceVar[] { var }; DecisionBuilder db = solver.MakePhase(seq_array, Solver.SEQUENCE_DEFAULT); solver.NewSearch(db); while (solver.NextSolution()) { foreach (int t in tasks) { Console.WriteLine(intervals[t].ToString()); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * KenKen puzzle. * * http://en.wikipedia.org/wiki/KenKen * """ * KenKen or KEN-KEN is a style of arithmetic and logical puzzle sharing * several characteristics with sudoku. The name comes from Japanese and * is translated as 'square wisdom' or 'cleverness squared'. * ... * The objective is to fill the grid in with the digits 1 through 6 such that: * * * Each row contains exactly one of each digit * * Each column contains exactly one of each digit * * Each bold-outlined group of cells is a cage containing digits which * achieve the specified result using the specified mathematical operation: * addition (+), * subtraction (-), * multiplication (x), * and division (/). * (Unlike in Killer sudoku, digits may repeat within a group.) * * ... * More complex KenKen problems are formed using the principles described * above but omitting the symbols +, -, x and /, thus leaving them as * yet another unknown to be determined. * """ * * The solution is: * * 5 6 3 4 1 2 * 6 1 4 5 2 3 * 4 5 2 3 6 1 * 3 4 1 2 5 6 * 2 3 6 1 4 5 * 1 2 5 6 3 4 * * * Also see http://www.hakank.org/or-tools/kenken2.py * though this C# model has another representation of * the problem instance. * */ private static void Solve() { Solver solver = new Solver("KenKen2"); // size of matrix int n = 6; IEnumerable <int> RANGE = Enumerable.Range(0, n); // For a better view of the problem, see // http://en.wikipedia.org/wiki/File:KenKenProblem.svg // hints // sum, the hints // Note: this is 1-based int[][] problem = { new int[] { 11, 1, 1, 2, 1 }, new int[] { 2, 1, 2, 1, 3 }, new int[] { 20, 1, 4, 2, 4 }, new int[] { 6, 1, 5, 1,6, 2, 6, 3, 6 }, new int[] { 3, 2, 2, 2, 3 }, new int[] { 3, 2, 5, 3, 5 }, new int[] { 240, 3, 1, 3,2, 4, 1, 4, 2 }, new int[] { 6, 3, 3, 3, 4 }, new int[] { 6, 4, 3, 5, 3 }, new int[] { 7, 4, 4, 5,4, 5, 5 }, new int[] { 30, 4, 5, 4, 6 }, new int[] { 6, 5, 1, 5, 2 }, new int[] { 9, 5, 6, 6, 6 }, new int[] { 8, 6, 1, 6,2, 6, 3 }, new int[] { 2, 6, 4, 6, 5 } }; int num_p = problem.GetLength(0); // Number of segments // // Decision variables // IntVar[,] x = solver.MakeIntVarMatrix(n, n, 1, n, "x"); IntVar[] x_flat = x.Flatten(); // // Constraints // // // alldifferent rows and columns foreach (int i in RANGE) { // rows solver.Add((from j in RANGE select x[i, j]).ToArray().AllDifferent()); // cols solver.Add((from j in RANGE select x[j, i]).ToArray().AllDifferent()); } // Calculate the segments for (int i = 0; i < num_p; i++) { int[] segment = problem[i]; // Remove the sum from the segment int len = segment.Length - 1; int[] s2 = new int[len]; Array.Copy(segment, 1, s2, 0, len); // sum this segment calc(solver, s2, x, segment[0]); } // // Search // DecisionBuilder db = solver.MakePhase(x_flat, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db); while (solver.NextSolution()) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { Console.Write(x[i, j].Value() + " "); } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Solves a set covering deployment problem. * See See http://www.hakank.org/or-tools/set_covering_deployment.py * */ private static void Solve() { Solver solver = new Solver("SetCoveringDeployment"); // // data // // From http://mathworld.wolfram.com/SetCoveringDeployment.html string[] countries = { "Alexandria", "Asia Minor", "Britain", "Byzantium", "Gaul", "Iberia", "Rome", "Tunis" }; int n = countries.Length; // the incidence matrix (neighbours) int[,] mat = { { 0, 1, 0, 1, 0, 0, 1, 1 }, { 1, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0 }, { 0, 0, 1, 0, 0, 1, 1, 0 }, { 0, 0, 1, 0, 1, 0, 1, 1 }, { 1, 0, 0, 1, 1, 1, 0, 1 }, { 1, 0, 0, 0, 0, 1, 1, 0 } }; // // Decision variables // // First army IntVar[] x = solver.MakeIntVarArray(n, 0, 1, "x"); // Second (reserve) army IntVar[] y = solver.MakeIntVarArray(n, 0, 1, "y"); // total number of armies IntVar num_armies = (x.Sum() + y.Sum()).Var(); // // Constraints // // // Constraint 1: There is always an army in a city // (+ maybe a backup) // Or rather: Is there a backup, there // must be an an army // for (int i = 0; i < n; i++) { solver.Add(x[i] >= y[i]); } // // Constraint 2: There should always be an backup // army near every city // for (int i = 0; i < n; i++) { IntVar[] count_neighbours = ( from j in Enumerable.Range(0, n) where mat[i, j] == 1 select(y[j])).ToArray(); solver.Add((x[i] + count_neighbours.Sum()) >= 1); } // // objective // OptimizeVar objective = num_armies.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db, objective); while (solver.NextSolution()) { Console.WriteLine("num_armies: " + num_armies.Value()); for (int i = 0; i < n; i++) { if (x[i].Value() == 1) { Console.Write("Army: " + countries[i] + " "); } if (y[i].Value() == 1) { Console.WriteLine(" Reverse army: " + countries[i]); } } Console.WriteLine("\n"); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Solves a set covering problem. * See See http://www.hakank.org/or-tools/set_covering3.py * */ private static void Solve() { Solver solver = new Solver("SetCovering3"); // // data // // Set covering problem from // Katta G. Murty: 'Optimization Models for Decision Making', // page 302f // http://ioe.engin.umich.edu/people/fac/books/murty/opti_model/junior-7.pdf int num_groups = 6; int num_senators = 10; // which group does a senator belong to? int[,] belongs = { { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, // 1 southern { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, // 2 northern { 0, 1, 1, 0, 0, 0, 0, 1, 1, 1 }, // 3 liberals { 1, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, // 4 conservative { 0, 0, 1, 1, 1, 1, 1, 0, 1, 0 }, // 5 democrats { 1, 1, 0, 0, 0, 0, 0, 1, 0, 1 } }; // 6 republicans // // Decision variables // IntVar[] x = solver.MakeIntVarArray(num_senators, 0, 1, "x"); // number of assigned senators, to be minimized IntVar z = x.Sum().Var(); // // Constraints // // ensure that each group is covered by at least // one senator for (int i = 0; i < num_groups; i++) { IntVar[] b = new IntVar[num_senators]; for (int j = 0; j < num_senators; j++) { b[j] = (x[j] * belongs[i, j]).Var(); } solver.Add(b.Sum() >= 1); } // // objective // OptimizeVar objective = z.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db, objective); while (solver.NextSolution()) { Console.WriteLine("z: " + z.Value()); Console.Write("x: "); for (int j = 0; j < num_senators; j++) { Console.Write(x[j].Value() + " "); } Console.WriteLine(); // More details for (int j = 0; j < num_senators; j++) { if (x[j].Value() == 1) { Console.Write("Senator " + (1 + j) + " belongs to these groups: "); for (int i = 0; i < num_groups; i++) { if (belongs[i, j] == 1) { Console.Write((1 + i) + " "); } } Console.WriteLine(); } } } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Combinatorial auction. * * This is a more general model for the combinatorial example * in the Numberjack Tutorial, pages 9 and 24 (slides 19/175 and * 51/175). * * See http://www.hakank.org/or-tools/combinatorial_auction2.py * * The original and more talkative model is here: * http://www.hakank.org/numberjack/combinatorial_auction.py * */ private static void Solve() { Solver solver = new Solver("CombinatorialAuction2"); // // Data // int n = 5; // the items for each bid int[][] items = { new int[] { 0, 1 }, // A,B new int[] { 0, 2 }, // A, C new int[] { 1, 3 }, // B,D new int[] { 1,2, 3 }, // B,C,D new int[] { 0 } // A }; int[] bid_ids = { 0, 1, 2, 3 }; int[] bid_amount = { 10, 20, 30, 40, 14 }; // // Decision variables // IntVar[] x = solver.MakeIntVarArray(n, 0, 1, "x"); IntVar z = x.ScalProd(bid_amount).VarWithName("z"); // // Constraints // foreach (int bid_id in bid_ids) { var tmp2 = (from item in Enumerable.Range(0, n) from i in Enumerable.Range(0, items[item].Length) where items [item] [i] == bid_id select x[item]); solver.Add(tmp2.ToArray().Sum() <= 1); } // // Objective // OptimizeVar obj = z.Maximize(1); // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.Write("z: {0,2} x: ", z.Value()); for (int i = 0; i < n; i++) { Console.Write(x[i].Value() + " "); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Discrete tomography * * Problem from http://eclipse.crosscoreop.com/examples/tomo.ecl.txt * """ * This is a little 'tomography' problem, taken from an old issue * of Scientific American. * * A matrix which contains zeroes and ones gets "x-rayed" vertically and * horizontally, giving the total number of ones in each row and column. * The problem is to reconstruct the contents of the matrix from this * information. Sample run: * * ?- go. * 0 0 7 1 6 3 4 5 2 7 0 0 * 0 * 0 * 8 * * * * * * * * * 2 * * * 6 * * * * * * * 4 * * * * * 5 * * * * * * 3 * * * * 7 * * * * * * * * 0 * 0 * * Eclipse solution by Joachim Schimpf, IC-Parc * """ * * See http://www.hakank.org/or-tools/discrete_tomography.py * */ private static void Solve(int[] rowsums, int[] colsums) { Solver solver = new Solver("DiscreteTomography"); // // Data // int r = rowsums.Length; int c = colsums.Length; Console.Write("rowsums: "); for (int i = 0; i < r; i++) { Console.Write(rowsums[i] + " "); } Console.Write("\ncolsums: "); for (int j = 0; j < c; j++) { Console.Write(colsums[j] + " "); } Console.WriteLine("\n"); // // Decision variables // IntVar[,] x = solver.MakeIntVarMatrix(r, c, 0, 1, "x"); IntVar[] x_flat = x.Flatten(); // // Constraints // // row sums for (int i = 0; i < r; i++) { var tmp = from j in Enumerable.Range(0, c) select x[i, j]; solver.Add(tmp.ToArray().Sum() == rowsums[i]); } // cols sums for (int j = 0; j < c; j++) { var tmp = from i in Enumerable.Range(0, r) select x[i, j]; solver.Add(tmp.ToArray().Sum() == colsums[j]); } // // Search // DecisionBuilder db = solver.MakePhase(x_flat, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db); while (solver.NextSolution()) { for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { Console.Write("{0} ", x[i, j].Value() == 1 ? "#" : "."); } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Post office problem. * * Problem statement: * http://www-128.ibm.com/developerworks/linux/library/l-glpk2/ * * From Winston 'Operations Research: Applications and Algorithms': * """ * A post office requires a different number of full-time employees working * on different days of the week [summarized below]. Union rules state that * each full-time employee must work for 5 consecutive days and then receive * two days off. For example, an employee who works on Monday to Friday * must be off on Saturday and Sunday. The post office wants to meet its * daily requirements using only full-time employees. Minimize the number * of employees that must be hired. * * To summarize the important information about the problem: * * Every full-time worker works for 5 consecutive days and takes 2 days off * - Day 1 (Monday): 17 workers needed * - Day 2 : 13 workers needed * - Day 3 : 15 workers needed * - Day 4 : 19 workers needed * - Day 5 : 14 workers needed * - Day 6 : 16 workers needed * - Day 7 (Sunday) : 11 workers needed * * The post office needs to minimize the number of employees it needs * to hire to meet its demand. * """ * * Also see http://www.hakank.org/or-tools/post_office_problem2.py * */ private static void Solve() { Solver solver = new Solver("PostOfficeProblem2"); // // Data // // days 0..6, monday 0 int n = 7; int[] need = { 17, 13, 15, 19, 14, 16, 11 }; // Total cost for the 5 day schedule. // Base cost per day is 100. // Working saturday is 100 extra // Working sunday is 200 extra. int[] cost = { 500, 600, 800, 800, 800, 800, 700 }; // // Decision variables // // No. of workers starting at day i IntVar[] x = solver.MakeIntVarArray(n, 0, 100, "x"); IntVar total_cost = x.ScalProd(cost).Var(); IntVar num_workers = x.Sum().Var(); // // Constraints // for (int i = 0; i < n; i++) { IntVar s = (from j in Enumerable.Range(0, n) where j != (i + 5) % n && j != (i + 6) % n select x[j]) .ToArray() .Sum() .Var(); solver.Add(s >= need[i]); } // Add a limit for the cost solver.Add(total_cost <= 20000); // // objective // // OptimizeVar obj = total_cost.Minimize(100); // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine("num_workers: {0}", num_workers.Value()); Console.WriteLine("total_cost: {0}", total_cost.Value()); Console.Write("x: "); for (int i = 0; i < n; i++) { Console.Write(x[i].Value() + " "); } Console.WriteLine("\n"); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Assignment problem * * From Wayne Winston "Operations Research", * Assignment Problems, page 393f * (generalized version with added test column) * * See See http://www.hakank.org/or-tools/assignment.py * */ private static void Solve() { Solver solver = new Solver("Assignment"); // // data // // Problem instance // hakank: I added the fifth column to make it more // interesting int rows = 4; int cols = 5; int[,] cost = { { 14, 5, 8, 7, 15 }, { 2, 12, 6, 5, 3 }, { 7, 8, 3, 9, 7 }, { 2, 4, 6, 10, 1 } }; // // Decision variables // IntVar[,] x = solver.MakeBoolVarMatrix(rows, cols, "x"); IntVar[] x_flat = x.Flatten(); // // Constraints // // Exacly one assignment per row (task), // i.e. all rows must be assigned with one worker for (int i = 0; i < rows; i++) { solver.Add((from j in Enumerable.Range(0, cols) select x[i, j]).ToArray().Sum() == 1); } // At most one assignments per column (worker) for (int j = 0; j < cols; j++) { solver.Add((from i in Enumerable.Range(0, rows) select x[i, j]).ToArray().Sum() <= 1); } // Total cost IntVar total_cost = (from i in Enumerable.Range(0, rows) from j in Enumerable.Range(0, cols) select(cost[i, j] * x[i, j])).ToArray().Sum().Var(); // // objective // OptimizeVar objective = total_cost.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(x_flat, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db, objective); while (solver.NextSolution()) { Console.WriteLine("total_cost: {0}", total_cost.Value()); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { Console.Write(x[i, j].Value() + " "); } Console.WriteLine(); } Console.WriteLine(); Console.WriteLine("Assignments:"); for (int i = 0; i < rows; i++) { Console.Write("Task " + i); for (int j = 0; j < cols; j++) { if (x[i, j].Value() == 1) { Console.WriteLine(" is done by " + j); } } } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Hidato puzzle in Google CP Solver. * * http://www.hidato.com/ * """ * Puzzles start semi-filled with numbered tiles. * The first and last numbers are circled. * Connect the numbers together to win. Consecutive * number must touch horizontally, vertically, or * diagonally. * """ * * This is a port of the Python model hidato_table.py * made by Laurent Perron (using AllowedAssignments), * based on my (much slower) model hidato.py. * */ private static void Solve(int model = 1) { Solver solver = new Solver("HidatoTable"); // // models, a 0 indicates an open cell which number is not yet known. // int[,] puzzle = null; if (model == 1) { // Simple problem // Solution 1: // 6 7 9 // 5 2 8 // 1 4 3 int[,] puzzle1 = { { 6, 0, 9 }, { 0, 2, 8 }, { 1, 0, 0 } }; puzzle = puzzle1; } else if (model == 2) { int[,] puzzle2 = { { 0, 44, 41, 0, 0, 0, 0 }, { 0, 43, 0, 28, 29, 0, 0 }, { 0, 1, 0, 0, 0, 33, 0 }, { 0, 2, 25, 4, 34, 0, 36 }, { 49, 16, 0, 23, 0, 0, 0 }, { 0, 19, 0, 0, 12, 7, 0 }, { 0, 0, 0, 14, 0, 0, 0 } }; puzzle = puzzle2; } else if (model == 3) { // Problems from the book: // Gyora Bededek: "Hidato: 2000 Pure Logic Puzzles" // Problem 1 (Practice) int[,] puzzle3 = { { 0, 0, 20, 0, 0 }, { 0, 0, 0, 16, 18 }, { 22, 0, 15, 0, 0 }, { 23, 0, 1, 14, 11 }, { 0, 25, 0, 0, 12 } }; puzzle = puzzle3; } else if (model == 4) { // problem 2 (Practice) int[,] puzzle4 = { { 0, 0, 0, 0, 14 }, { 0, 18, 12, 0, 0 }, { 0, 0, 17, 4, 5 }, { 0, 0, 7, 0, 0 }, { 9, 8, 25, 1, 0 } }; puzzle = puzzle4; } else if (model == 5) { // problem 3 (Beginner) int[,] puzzle5 = { { 0, 26, 0, 0, 0, 18 }, { 0, 0, 27, 0, 0, 19 }, { 31, 23, 0, 0, 14, 0 }, { 0, 33, 8, 0, 15, 1 }, { 0, 0, 0, 5, 0, 0 }, { 35, 36, 0, 10, 0, 0 } }; puzzle = puzzle5; } else if (model == 6) { // Problem 15 (Intermediate) int[,] puzzle6 = { { 64, 0, 0, 0, 0, 0, 0, 0 }, { 1, 63, 0, 59, 15, 57, 53, 0 }, { 0, 4, 0, 14, 0, 0, 0, 0 }, { 3, 0, 11, 0, 20, 19, 0, 50 }, { 0, 0, 0, 0, 22, 0, 48, 40 }, { 9, 0, 0, 32, 23, 0, 0, 41 }, { 27, 0, 0, 0, 36, 0, 46, 0 }, { 28, 30, 0, 35, 0, 0, 0, 0 } }; puzzle = puzzle6; } int r = puzzle.GetLength(0); int c = puzzle.GetLength(1); Console.WriteLine(); Console.WriteLine("----- Solving problem {0} -----", model); Console.WriteLine(); PrintMatrix(puzzle); // // Decision variables // IntVar[] positions = solver.MakeIntVarArray(r * c, 0, r * c - 1, "p"); // // Constraints // solver.Add(positions.AllDifferent()); // // Fill in the clues // for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (puzzle[i, j] > 0) { solver.Add(positions[puzzle[i, j] - 1] == i * c + j); } } } // Consecutive numbers much touch each other in the grid. // We use an allowed assignment constraint to model it. IntTupleSet close_tuples = BuildPairs(r, c); for (int k = 1; k < r * c - 1; k++) { IntVar[] tmp = new IntVar[] { positions[k], positions[k + 1] }; solver.Add(tmp.AllowedAssignments(close_tuples)); } // // Search // DecisionBuilder db = solver.MakePhase(positions, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db); int num_solution = 0; while (solver.NextSolution()) { num_solution++; PrintOneSolution(positions, r, c, num_solution); } Console.WriteLine("\nSolutions: " + solver.Solutions()); Console.WriteLine("WallTime: " + solver.WallTime() + "ms "); Console.WriteLine("Failures: " + solver.Failures()); Console.WriteLine("Branches: " + solver.Branches()); solver.EndSearch(); }
/** * * Solves the Quasigroup Completion problem. * See http://www.hakank.org/or-tools/quasigroup_completion.py * */ private static void Solve() { Solver solver = new Solver("QuasigroupCompletion"); // // data // Console.WriteLine("Problem:"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { Console.Write(problem[i, j] + " "); } Console.WriteLine(); } Console.WriteLine(); // // Decision variables // IntVar[,] x = solver.MakeIntVarMatrix(n, n, 1, n, "x"); IntVar[] x_flat = x.Flatten(); // // Constraints // for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (problem[i, j] > X) { solver.Add(x[i, j] == problem[i, j]); } } } // // rows and columns must be different // // rows for (int i = 0; i < n; i++) { IntVar[] row = new IntVar[n]; for (int j = 0; j < n; j++) { row[j] = x[i, j]; } solver.Add(row.AllDifferent()); } // columns for (int j = 0; j < n; j++) { IntVar[] col = new IntVar[n]; for (int i = 0; i < n; i++) { col[i] = x[i, j]; } solver.Add(col.AllDifferent()); } // // Search // DecisionBuilder db = solver.MakePhase(x_flat, Solver.INT_VAR_SIMPLE, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db); int sol = 0; while (solver.NextSolution()) { sol++; Console.WriteLine("Solution #{0} ", sol + " "); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { Console.Write("{0} ", x[i, j].Value()); } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
public void NewSearch(DecisionBuilder db) { pinned_decision_builder_ = db; pinned_search_monitors_.Clear(); NewSearchAux(db); }
/** * * Lectures problem in Google CP Solver. * * Biggs: Discrete Mathematics (2nd ed), page 187. * """ * Suppose we wish to schedule six one-hour lectures, v1, v2, v3, v4, v5, v6. * Among the the potential audience there are people who wish to hear both * * - v1 and v2 * - v1 and v4 * - v3 and v5 * - v2 and v6 * - v4 and v5 * - v5 and v6 * - v1 and v6 * * How many hours are necessary in order that the lectures can be given * without clashes? * """ * * Note: This can be seen as a coloring problem. * * Also see http://www.hakank.org/or-tools/lectures.py * */ private static void Solve() { Solver solver = new Solver("Lectures"); // // The schedule requirements: // lecture a cannot be held at the same time as b // Note: 1-based (compensated in the constraints). int[,] g = { { 1, 2 }, { 1, 4 }, { 3, 5 }, { 2, 6 }, { 4, 5 }, { 5, 6 }, { 1, 6 } }; // number of nodes int n = 6; // number of edges int edges = g.GetLength(0); // // Decision variables // // // declare variables // IntVar[] v = solver.MakeIntVarArray(n, 0, n - 1, "v"); // Maximum color (hour) to minimize. // Note: since C# is 0-based, the // number of colors is max_c+1. IntVar max_c = v.Max().VarWithName("max_c"); // // Constraints // // Ensure that there are no clashes // also, adjust to 0-base. for (int i = 0; i < edges; i++) { solver.Add(v[g[i, 0] - 1] != v[g[i, 1] - 1]); } // Symmetry breaking: // - v0 has the color 0, // - v1 has either color 0 or 1 solver.Add(v[0] == 0); solver.Add(v[1] <= 1); // // Objective // OptimizeVar obj = max_c.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(v, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_MIN_VALUE); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine("\nmax hours: {0}", max_c.Value() + 1); Console.WriteLine( "v: " + String.Join(" ", (from i in Enumerable.Range(0, n) select v[i].Value()).ToArray())); for (int i = 0; i < n; i++) { Console.WriteLine("Lecture {0} at {1}h", i, v[i].Value()); } Console.WriteLine("\n"); } Console.WriteLine("\nSolutions: " + solver.Solutions()); Console.WriteLine("WallTime: " + solver.WallTime() + "ms "); Console.WriteLine("Failures: " + solver.Failures()); Console.WriteLine("Branches: " + solver.Branches()); solver.EndSearch(); }
public void NewSearch(DecisionBuilder db, SearchMonitor[] monitors) { pinned_decision_builder_ = db; pinned_search_monitors_.Clear(); pinned_search_monitors_.AddRange(monitors); NewSearchAux(db, monitors); }
/** * * Solves a set covering problem. * See See http://www.hakank.org/or-tools/set_covering.py * */ private static void Solve() { Solver solver = new Solver("SetCovering"); // // data // // Placing of firestations, from Winston 'Operations Research', // page 486. int min_distance = 15; int num_cities = 6; int[,] distance = { { 0, 10, 20, 30, 30, 20 }, { 10, 0, 25, 35, 20, 10 }, { 20, 25, 0, 15, 30, 20 }, { 30, 35, 15, 0, 15, 25 }, { 30, 20, 30, 15, 0, 14 }, { 20, 10, 20, 25, 14, 0 } }; // // Decision variables // IntVar[] x = solver.MakeIntVarArray(num_cities, 0, 1, "x"); IntVar z = x.Sum().Var(); // // Constraints // // ensure that all cities are covered for (int i = 0; i < num_cities; i++) { IntVar[] b = (from j in Enumerable.Range(0, num_cities) where distance[i, j] <= min_distance select x[j]) .ToArray(); solver.Add(b.Sum() >= 1); } // // objective // OptimizeVar objective = z.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(x, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT); solver.NewSearch(db, objective); while (solver.NextSolution()) { Console.WriteLine("z: {0}", z.Value()); Console.Write("x: "); for (int i = 0; i < num_cities; i++) { Console.Write(x[i].Value() + " "); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }