Books · Solving Puzzles through Mathematical Programming
Chapter 12
Monkey, Cat, and Dog
A monkey fills an grid with the numbers , each used exactly once. A cat computes the product of the numbers in each row; a dog computes the product of the numbers in each column. Both animals write their results as a list of numbers. Can the monkey fill in the grid so that the cat and the dog obtain the same list (as a multiset)?
The answer depends on . For it is no, by a two-line argument. For it is yes, as witnessed by the grid whose row products are and whose column products are : the same multiset. For the answer is yes, established constructively in each case by CP-SAT below. For the answer reverts to no — a surprising return of infeasibility — and the obstruction generalises to infinitely many larger .
Impossibility at
Write the grid as with . The row products are and the column products are . If the two multisets match, either and , which forces ; or and , which forces . Either way, two of the four cells carry the same number, contradicting the assumption that the four cells hold the four distinct numbers .
The programming model
A naive encoding introduces an integer variable per cell and a product-variable per row and per column, with on the cells and multiset equality on the product lists. The products for large are immense — , — which rules the naive encoding out. A much tighter formulation replaces products with exponent vectors.
Primes and exponents
For each prime , define to be the exponent of in the prime factorisation of . The product of a row is uniquely determined by its vector of prime exponents; two products are equal if and only if their exponent vectors are equal coordinate-by-coordinate. For each row and each prime the row’s total exponent of is and symmetrically for columns.
Cell-exponent variables
For each cell introduce an integer variable (with a single global constraint over the cells), and for each prime a companion variable representing . Link the two via an element constraint against the lookup table indexed by .
Multiset equality
The row and column product multisets are equal if and only if there exists a permutation such that, for every prime , This is encoded in CP-SAT by an integer permutation variable with , followed by an element constraint that equates to the -th entry of , for each prime .
A solver in fifty lines
from ortools.sat.python import cp_model
from sympy import primerange, factorint
def solve(n):
N = n * n
primes = list(primerange(2, N + 1))
v = {k: {p: 0 for p in primes} for k in range(1, N + 1)}
for k in range(2, N + 1):
for p, e in factorint(k).items():
v[k][p] = e
M = {p: max(v[k][p] for k in range(1, N + 1))
for p in primes}
m = cp_model.CpModel()
g = [[m.NewIntVar(1, N, "")
for _ in range(n)] for _ in range(n)]
m.AddAllDifferent([g[i][j]
for i in range(n)
for j in range(n)])
e = {}
for i in range(n):
for j in range(n):
idx = m.NewIntVar(0, N - 1, "")
m.Add(idx == g[i][j] - 1)
for p in primes:
tbl = [v[k][p] for k in range(1, N + 1)]
x = m.NewIntVar(0, M[p], "")
m.AddElement(idx, tbl, x)
e[(i, j, p)] = x
R, C = {}, {}
for i in range(n):
for p in primes:
r = m.NewIntVar(0, n * M[p], "")
m.Add(r == sum(e[(i, j, p)]
for j in range(n)))
R[(i, p)] = r
for j in range(n):
for p in primes:
c = m.NewIntVar(0, n * M[p], "")
m.Add(c == sum(e[(i, j, p)]
for i in range(n)))
C[(j, p)] = c
sigma = [m.NewIntVar(0, n - 1, "")
for _ in range(n)]
m.AddAllDifferent(sigma)
for i in range(n):
for p in primes:
col_list = [C[(j, p)] for j in range(n)]
tgt = m.NewIntVar(0, n * M[p], "")
m.AddElement(sigma[i], col_list, tgt)
m.Add(R[(i, p)] == tgt)
s = cp_model.CpSolver()
s.parameters.max_time_in_seconds = 60
st = s.Solve(m)
if st not in (cp_model.OPTIMAL, cp_model.FEASIBLE):
return None
return [[s.Value(g[i][j]) for j in range(n)]
for i in range(n)]
On a standard laptop the solver decides feasibility as follows:
The instance is Figure 12.1; representative solutions for and are Figures 12.2 and 12.3.
Why fails: large primes
The unexpected infeasibility at comes from a clean pigeonhole argument on large primes. A prime with divides exactly one value in , namely itself (since ). Whichever row contains the value is the only row whose product is divisible by , and similarly for columns. The bijection that witnesses multiset equality must therefore map the row containing to the column containing : this fixes one entry of per such prime.
Now count the primes in : There are ten “large primes” but only nine rows. By pigeonhole, two of these primes lie in the same row, at different columns. The bijection is forced to map that row to both columns at once, which is impossible. No solution can exist.
This reasoning extends: feasibility fails whenever where is the prime-counting function. The first offender is ; the next are (thirteen primes), (fourteen primes), and so on. By the prime-number theorem the left side grows like , so the inequality holds for all sufficiently large ; feasibility is therefore rare in the long run, and the feasible form a finite set.
The picture for small is then The large-prime inequality is satisfied at and and, by the prime-number-theorem growth, at every sufficiently large , so all but finitely many are infeasible; but it does not follow that every fails, since the inequality is not known to hold without exception, and establishing the precise infeasible set would require checking the remaining cases individually. The status of is in any case undetermined by the large-prime argument alone: there are exactly ten large primes in , so the pigeonhole is tight but not strict, and a dedicated longer search is required to settle it.
Sources. The monkey–cat–dog problem appears as a training problem in Problem Solving Strategies (Arthur Engel, ) and in various olympiad collections; the large-prime argument that rules out and all sufficiently large is due to multiple authors independently, perhaps first written up by R. Guy in Unsolved Problems in Number Theory. The feasibility of small is constructive but the constructions for are not particularly illuminating; CP-SAT’s rapid decisions are the only tidy proof that each is feasible. The general classification of feasible — which finite set exactly? — combines the large-prime argument (ruling out infinitely many ) with more delicate parity arguments at the remaining ; an elementary complete classification is not known to the author.