Le Zèbre de Lewis Carroll
Oui très bien

On peut résoudre ce problème par un solveur de problèmes de satisfaction de contrainte. Chaque attribut (“anglais”, “vin”, etc) est une variable. Les domaines sont les entiers de 1 à 5, correspondant au numéro de maison. Deux exception sont les variables “norvégien” et “lait” dont le domaine est un singleton, comme indiqué par les contraintes unaires de l’entrée.
Les autres contraintes sont toutes binaires. On peut modéliser et résoudre le problème comme suit.
#!/usr/bin/env python3
import sys
from constraint_programming import constraint_program
# chaque attribut est une variable
varnames = [
["norvégien", "anglais", "espagnol", "ukrainien", "japonais"],
["bleue", "rouge", "verte", "jaune", "blanche"],
["lait", "café", "thé", "vin", "eau"],
["kools", "cravens", "old golds", "gitanes", "chesterfields"],
["chien", "escargot", "renard", "cheval", "zèbre"]
]
# les maisons sont numérotés de 1 à 5
DOM = [1,2,3,4,5]
EQUAL = set((u,u) for u in DOM)
DIFF = set((u,v) for u in DOM for v in DOM if u != v)
SUCC = set((u, u+1) for u in [1,2,3,4])
PREC = set((u+1, u) for u in [1,2,3,4])
NEXT = SUCC | PREC
var = {}
for categorie in varnames:
for name in categorie:
var[name] = set(DOM)
# norvégien = 1
var["norvégien"] = {1}
# lait = 3
var["lait"] = {3}
P = constraint_program(var)
# tout différent
for categorie in varnames:
for a in categorie:
for b in categorie:
if a < b:
P.add_constraint(a, b, DIFF)
# bleue = norvégien + 1
P.add_constraint("bleue", "norvégien", PREC)
# anglais = rouge
P.add_constraint("anglais", "rouge", EQUAL)
# verte = café
P.add_constraint("verte", "café", EQUAL)
# jaune = kools
P.add_constraint("jaune", "kools", EQUAL)
# blanche = verte + 1
P.add_constraint("blanche", "verte", PREC)
# espagnol = chien
P.add_constraint("espagnol", "chien", EQUAL)
# ukrainien = thé
P.add_constraint("ukrainien", "thé", EQUAL)
# japonais = cravens
P.add_constraint("japonais", "cravens", EQUAL)
# old golds = escargot
P.add_constraint("old golds", "escargot", EQUAL)
# gitanes = vin
P.add_constraint("gitanes", "vin", EQUAL)
# (chesterfields = renard + 1) ou (chesterfields = renard - 1)
P.add_constraint("chesterfields", "renard", NEXT)
# (kools = cheval + 1) ou (kools = cheval - 1)
P.add_constraint("kools", "cheval", NEXT)
# P.print_tree = True
sol = P.solve()
for maison in DOM:
print("%-15i" % maison, end="")
print()
for categorie in varnames:
for maison in DOM:
for name in categorie:
if sol[name] == maison:
print("%-15s" % name, end="")
print()
Le programme affiche l’unique solution comme suit.
| maison 1 | maison 2 | maison 3 | maison 4 | maison 5 |
|---|---|---|---|---|
| norvégien | ukrainien | anglais | japonais | espagnol |
| jaune | bleue | rouge | verte | blanche |
| eau | thé | lait | café | vin |
| kools | chesterfields | old golds | cravens | gitanes |
| renard | cheval | escargot | zèbre | chien |