You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Sudoku</strong> con AMPL<br />
Stefano Nasini<br />
Dept. of Statistics and Operations Research<br />
Universitat Politécnica de Catalunya<br />
La solución de un sudoku siempre es un cuadrado latino, es decir, una matriz de n×n elementos, en la<br />
que cada casilla está ocupada por uno de los n símbolos de tal modo que cada uno de ellos aparece<br />
exactamente una vez en cada columna y en cada fila, aunque el recíproco en general no es cierto ya que el<br />
sudoku establece la restricción añadida de que no se puede repetir un mismo número en una región.<br />
Para costruir un modelo de optimizaciòn que nos permita solucionar un <strong>Sudoku</strong> hace falta convertir<br />
en costricciones de un problema de programaciòn matematica las que son las reglas del juego.<br />
Dichas reglas son rellenar una cuadrícula de 9 × 9 celdas (81 casillas) dividida en subcuadrículas de<br />
3 × 3 (también llamadas "cajas" o "regiones") con las cifras del 1 al 9 partiendo de algunos números ya<br />
dispuestos en algunas de las celdas. El sudoku que querriamos solucionar es el siguiente:<br />
Antes que todo, nuestras variables de deciciones han de ser variables binarias que nos informan de la<br />
presencia o absencia de una cifra en una casilla. Asì que dicha variable de deciciòn estarà definida por tres<br />
subindices: fila, columna, digito, y tomaràvalor 1 en el caso en el que en una determinada casilla<br />
(identificada por sus coordenadas) hay un determinado digito.<br />
Imponemos que en cada celda solo haya un digito y no màs.<br />
1
9<br />
∑<br />
c=<br />
1<br />
Cell<br />
abc<br />
= 1<br />
Imponemos que un digito de 0 a 9 aparezca solo una vez por cada fila.<br />
9<br />
∑<br />
a=<br />
1<br />
Cell<br />
abc<br />
= 1<br />
Imponemos que un digito de 0 a 9 aparezca solo una vez por cada columna.<br />
9<br />
∑<br />
b=<br />
1<br />
Cell<br />
abc<br />
= 1<br />
Imponemos que en un cuadrado 3x3 un digito aparezca una sola vez.<br />
3<br />
3<br />
∑∑<br />
a= 1 b=<br />
1<br />
Cell<br />
abc<br />
= 1<br />
Imponemos que en un cuadrado 3x3 un dado digito aparezca una sola vez.<br />
3<br />
3<br />
∑∑<br />
a= 1 b=<br />
1<br />
6<br />
3<br />
∑∑<br />
a= 4 b=<br />
1<br />
9<br />
3<br />
∑∑<br />
a= 7 b=<br />
1<br />
3<br />
6<br />
Cell<br />
abc<br />
= 1 ∑∑Cell abc<br />
= 1 ∑∑Cell<br />
a= 1 b=<br />
4<br />
6<br />
6<br />
3<br />
9<br />
a= 1 b=<br />
7<br />
Cell<br />
abc<br />
= 1 ∑∑Cell abc<br />
= 1 ∑∑Cell<br />
a= 4 b=<br />
4<br />
7<br />
6<br />
6<br />
7<br />
a= 4 b=<br />
7<br />
Cell<br />
abc<br />
= 1 ∑∑Cell abc<br />
= 1 ∑∑Cell<br />
a= 7 b=<br />
4<br />
9<br />
9<br />
a= 7 b=<br />
7<br />
abc<br />
abc<br />
abc<br />
= 1<br />
= 1<br />
= 1<br />
De dicho problema buscamo una cualquiera soluciòn factible, asì que no hace falta poner ninguna<br />
funciòn objetivo. Lo implementamos en AMPL como problema de programaciòn entera de la forma<br />
siguiente.<br />
var Cell{1..9,1..9,1..9} binary;<br />
minimize Niente;<br />
subject to Somma_1 {a in 1..9,b in 1..9}:<br />
sum{c in 1..9} Cell[a,b,c]=1;<br />
subject to Somma_2 {a in 1..9,c in 1..9}:<br />
sum{b in 1..9} Cell[a,b,c]=1;<br />
subject to Somma_3 {b in 1..9,c in 1..9}:<br />
sum{a in 1..9} Cell[a,b,c]=1;<br />
subject to Riquadri_1 {c in 1..9}:<br />
sum{a in 1..3,b in 1..3} Cell[a,b,c]=1;<br />
subject to Riquadri_2 {c in 1..9}:<br />
sum{a in 1..3,b in 4..6} Cell[a,b,c]=1;<br />
subject to Riquadri_3 {c in 1..9}:<br />
sum{a in 1..3,b in 7..9} Cell[a,b,c]=1;<br />
subject to Riquadri_4 {c in 1..9}:<br />
2
sum{a in 4..6,b in 4..6} Cell[a,b,c]=1;<br />
subject to Riquadri_5 {c in 1..9}:<br />
sum{a in 4..6,b in 1..3} Cell[a,b,c]=1;<br />
subject to Riquadri_6 {c in 1..9}:<br />
sum{a in 4..6,b in 7..9} Cell[a,b,c]=1;<br />
subject to Riquadri_7 {c in 1..9}:<br />
sum{a in 7..9,b in 1..3} Cell[a,b,c]=1;<br />
subject to Riquadri_8 {c in 1..9}:<br />
sum{a in 7..9,b in 4..6} Cell[a,b,c]=1;<br />
subject to Riquadri_9 {c in 1..9}:<br />
sum{a in 7..9,b in 7..9} Cell[a,b,c]=1;<br />
subject to C1: Cell[1,1,5]=1;<br />
subject to C2: Cell[1,2,3]=1;<br />
subject to C3: Cell[1,5,7]=1;<br />
subject to C4: Cell[2,1,6]=1;<br />
subject to C5: Cell[2,4,1]=1;<br />
subject to C6: Cell[2,5,9]=1;<br />
subject to C7: Cell[2,6,5]=1;<br />
subject to C8: Cell[3,2,9]=1;<br />
subject to C9: Cell[3,3,8]=1;<br />
subject to C10: Cell[3,8,6]=1;<br />
subject to C11: Cell[4,1,8]=1;<br />
subject to C12: Cell[4,5,6]=1;<br />
subject to C13: Cell[4,9,3]=1;<br />
subject to C14: Cell[5,1,4]=1;<br />
subject to C15: Cell[5,4,8]=1;<br />
subject to C16: Cell[5,6,3]=1;<br />
subject to C17: Cell[5,9,1]=1;<br />
subject to C18: Cell[6,1,7]=1;<br />
subject to C19: Cell[6,5,2]=1;<br />
subject to C20: Cell[6,5,2]=1;<br />
subject to C21: Cell[6,9,6]=1;<br />
subject to C22: Cell[7,2,6]=1;<br />
subject to C23: Cell[7,7,2]=1;<br />
subject to C24: Cell[7,8,8]=1;<br />
subject to C25: Cell[8,4,4]=1;<br />
subject to C26: Cell[8,5,1]=1;<br />
subject to C27: Cell[8,6,9]=1;<br />
subject to C28: Cell[8,9,5]=1;<br />
subject to C29: Cell[9,5,8]=1;<br />
subject to C30: Cell[9,8,7]=1;<br />
subject to C31: Cell[9,9,9]=1;<br />
En el ultimo grupo de constricciones hemos impuesto los valores predefinidos de algunas celdas,<br />
como mostra la representaciòn grafica de la pagina anterior. Utilizando CPLEX como solver, optenemos la<br />
siguiente soluciòn binaria de nuestro problema.<br />
Cada matriz corresponde a una fila del sudoku. Los valores de fila de la matriz corresponden a las<br />
columnas del sudoku y los valores en columna a cala digito que puede ser introducido. Por ejemplo el valor<br />
Cell[1,1,1]=0 nos dice que en la celda(1,1) del sudoku el valor 1 no esta presente.<br />
ampl: model sudoku1.mod;<br />
ampl: solve;<br />
Solution determined by presolve;<br />
objective Niente = 0.<br />
3
ampl: display Cell;<br />
Cell [1,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 0 0 0 1 0 0 0 0<br />
2 0 0 1 0 0 0 0 0 0<br />
3 0 0 0 1 0 0 0 0 0<br />
4 0 0 0 0 0 1 0 0 0<br />
5 0 0 0 0 0 0 1 0 0<br />
6 0 0 0 0 0 0 0 1 0<br />
7 0 0 0 0 0 0 0 0 1<br />
8 1 0 0 0 0 0 0 0 0<br />
9 0 1 0 0 0 0 0 0 0<br />
[2,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 0 0 0 0 1 0 0 0<br />
2 0 0 0 0 0 0 1 0 0<br />
3 0 1 0 0 0 0 0 0 0<br />
4 1 0 0 0 0 0 0 0 0<br />
5 0 0 0 0 0 0 0 0 1<br />
6 0 0 0 0 1 0 0 0 0<br />
7 0 0 1 0 0 0 0 0 0<br />
8 0 0 0 1 0 0 0 0 0<br />
9 0 0 0 0 0 0 0 1 0<br />
[3,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 1 0 0 0 0 0 0 0 0<br />
2 0 0 0 0 0 0 0 0 1<br />
3 0 0 0 0 0 0 0 1 0<br />
4 0 0 1 0 0 0 0 0 0<br />
5 0 0 0 1 0 0 0 0 0<br />
6 0 1 0 0 0 0 0 0 0<br />
7 0 0 0 0 1 0 0 0 0<br />
8 0 0 0 0 0 1 0 0 0<br />
9 0 0 0 0 0 0 1 0 0<br />
[4,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 0 0 0 0 0 0 1 0<br />
2 0 0 0 0 1 0 0 0 0<br />
3 0 0 0 0 0 0 0 0 1<br />
4 0 0 0 0 0 0 1 0 0<br />
5 0 0 0 0 0 1 0 0 0<br />
6 1 0 0 0 0 0 0 0 0<br />
7 0 0 0 1 0 0 0 0 0<br />
8 0 1 0 0 0 0 0 0 0<br />
9 0 0 1 0 0 0 0 0 0<br />
[5,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 0 0 1 0 0 0 0 0<br />
2 0 1 0 0 0 0 0 0 0<br />
3 0 0 0 0 0 1 0 0 0<br />
4 0 0 0 0 0 0 0 1 0<br />
5 0 0 0 0 1 0 0 0 0<br />
6 0 0 1 0 0 0 0 0 0<br />
7 0 0 0 0 0 0 1 0 0<br />
8 0 0 0 0 0 0 0 0 1<br />
9 1 0 0 0 0 0 0 0 0<br />
[6,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 0 0 0 0 0 1 0 0<br />
2 1 0 0 0 0 0 0 0 0<br />
3 0 0 1 0 0 0 0 0 0<br />
4 0 0 0 0 0 0 0 0 1<br />
5 0 1 0 0 0 0 0 0 0<br />
4
6 0 0 0 1 0 0 0 0 0<br />
7 0 0 0 0 0 0 0 1 0<br />
8 0 0 0 0 1 0 0 0 0<br />
9 0 0 0 0 0 1 0 0 0<br />
[7,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 0 0 0 0 0 0 0 1<br />
2 0 0 0 0 0 1 0 0 0<br />
3 1 0 0 0 0 0 0 0 0<br />
4 0 0 0 0 1 0 0 0 0<br />
5 0 0 1 0 0 0 0 0 0<br />
6 0 0 0 0 0 0 1 0 0<br />
7 0 1 0 0 0 0 0 0 0<br />
8 0 0 0 0 0 0 0 1 0<br />
9 0 0 0 1 0 0 0 0 0<br />
[8,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 1 0 0 0 0 0 0 0<br />
2 0 0 0 0 0 0 0 1 0<br />
3 0 0 0 0 0 0 1 0 0<br />
4 0 0 0 1 0 0 0 0 0<br />
5 1 0 0 0 0 0 0 0 0<br />
6 0 0 0 0 0 0 0 0 1<br />
7 0 0 0 0 0 1 0 0 0<br />
8 0 0 1 0 0 0 0 0 0<br />
9 0 0 0 0 1 0 0 0 0<br />
[9,*,*]<br />
: 1 2 3 4 5 6 7 8 9 :=<br />
1 0 0 1 0 0 0 0 0 0<br />
2 0 0 0 1 0 0 0 0 0<br />
3 0 0 0 0 1 0 0 0 0<br />
4 0 1 0 0 0 0 0 0 0<br />
5 0 0 0 0 0 0 0 1 0<br />
6 0 0 0 0 0 1 0 0 0<br />
7 1 0 0 0 0 0 0 0 0<br />
8 0 0 0 0 0 0 1 0 0<br />
9 0 0 0 0 0 0 0 0 1<br />
;<br />
ampl:<br />
Introduciendo en la tabla del sudoku dicha soluciòn obtenemos el siguiente resultado.<br />
5 3 4 6 7 8 9 1 2<br />
6 7 2 1 9 5 3 4 8<br />
1 9 8 3 4 2 5 6 7<br />
8 5 9 7 6 1 4 2 5<br />
4 2 6 8 5 3 7 9 1<br />
7 1 3 9 2 4 8 5 6<br />
9 6 1 5 3 7 2 8 4<br />
2 8 7 4 1 9 6 3 5<br />
3 4 5 2 8 6 1 7 9<br />
5