-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathsendmoremoney_binary.cc
144 lines (126 loc) · 4.79 KB
/
sendmoremoney_binary.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Solves the classic puzzle SEND+MORE=MONEY using EasySCIP.
// by Ricardo Bittencourt 2013
#include <iostream>
#include "easyscip.h"
using namespace std;
using namespace easyscip;
int main() {
// Create a MIPSolver using EasySCIP.
MIPSolver solver;
// Add one binary variable for each assignment between letter and digit.
// We're looking only for feasibility, not optimality, so we're
// setting the objective coefficient for all variables to 0.
string unknowns = "sendmory";
vector< vector<Variable> > var(unknowns.size());
for (int i = 0; i < int(unknowns.size()); i++) {
for (int j = 0; j <= 9; j++) {
var[i].push_back(solver.binary_variable(0));
}
}
// Add one binary variable for each carry.
// Again the coefficient is zero.
vector<Variable> carry;
for (int i = 0; i < 4; i++) {
carry.push_back(solver.binary_variable(0));
}
// Add a constraint for the last column: D + E = Y + 10 * carry[0];
// This is done by a linear equation, where each letter is added ten times:
// 0*D_0 + 1*D_1 + .... + 9*D_9
// + 0*E_0 + 1*E_1 + .... + 9*E_9
// - 0*Y_0 - 1*Y_1 - .... - 9*Y_9
// - 10*carry[0] == 0
// Here we're creating the constraint.
Constraint column0 = solver.constraint();
// Add all relevant variables to the constraint.
for (int i = 0; i <= 9; i++) {
column0.add_variable(var[unknowns.find('d')][i], i);
column0.add_variable(var[unknowns.find('e')][i], i);
column0.add_variable(var[unknowns.find('y')][i], -i);
}
column0.add_variable(carry[0], -10);
// Commit the constraint to the solver.
// The solver uses inequalities of the form lhs <= x <= rhs,
// but we can turn that into an equality by setting lhs = rhs.
// The Constraint object can be deleted after it's committed.
// In this case, it will be deleted when it falls out of the scope.
column0.commit(0, 0);
// Constraint: N + R + carry[0] = E + 10 * carry[1];
Constraint column1 = solver.constraint();
for (int i = 0; i <= 9; i++) {
column1.add_variable(var[unknowns.find('n')][i], i);
column1.add_variable(var[unknowns.find('r')][i], i);
column1.add_variable(var[unknowns.find('e')][i], -i);
}
column1.add_variable(carry[0], 1);
column1.add_variable(carry[1], -10);
column1.commit(0, 0);
// Constraint: E + O + carry[1] = N + 10 * carry[2];
Constraint column2 = solver.constraint();
for (int i = 0; i <= 9; i++) {
column2.add_variable(var[unknowns.find('e')][i], i);
column2.add_variable(var[unknowns.find('o')][i], i);
column2.add_variable(var[unknowns.find('n')][i], -i);
}
column2.add_variable(carry[1], 1);
column2.add_variable(carry[2], -10);
column2.commit(0, 0);
// Constraint: S + M + carry[2] = O + 10 * carry[3];
Constraint column3 = solver.constraint();
for (int i = 0; i <= 9; i++) {
column3.add_variable(var[unknowns.find('s')][i], i);
column3.add_variable(var[unknowns.find('m')][i], i);
column3.add_variable(var[unknowns.find('o')][i], -i);
}
column3.add_variable(carry[2], 1);
column3.add_variable(carry[3], -10);
column3.commit(0, 0);
// Constraint: carry[3] = M;
Constraint column4 = solver.constraint();
for (int i = 0; i <= 9; i++) {
column4.add_variable(var[unknowns.find('m')][i], -i);
}
column4.add_variable(carry[3], 1);
column4.commit(0, 0);
// Each letter must be assigned to exactly one digit.
// We model this as one linear constraint by letter, of the form:
// L_0 + L_1 + ... + L_9 = 1
for (int i = 0; i < int(unknowns.size()); i++) {
Constraint letter = solver.constraint();
for (int j = 0; j <= 9; j++) {
letter.add_variable(var[i][j], 1);
}
letter.commit(1, 1);
}
// Each digit must be assigned to no more than one letter.
// We model this as one linear constraint by letter, of the form:
// 0 <= D_0 + D_1 + ... + D_9 <= 1
// This is an inequality since there may be digits without a letter assigned.
for (int j = 0; j <= 9; j++) {
Constraint digit = solver.constraint();
for (int i = 0; i < int(unknowns.size()); i++) {
digit.add_variable(var[i][j], 1);
}
digit.commit(0, 1);
}
// S is the first digit of a number, cannot be zero.
Constraint s_first = solver.constraint();
s_first.add_variable(var[0][0], 1);
s_first.commit(0, 0);
// M is the first digit of a number, cannot be zero.
Constraint m_first = solver.constraint();
m_first.add_variable(var[4][0], 1);
m_first.commit(0, 0);
// Solve the MIP model.
Solution sol = solver.solve();
// Print solution.
for (int i = 0; i < int(unknowns.size()); i++) {
for (int j = 0; j <= 9; j++) {
if (sol.value(var[i][j]) > 0.5) {
cout << unknowns[i] << " = " << j << "\n";
}
}
}
// No need to worry about memory management, everything is released
// when the objects are deleted after falling out of scope.
return 0;
}