Documente Academic
Documente Profesional
Documente Cultură
v Introducción 2
v El problema de las ocho reinas 16
v El problema de la suma de
subconjuntos 26
v Coloreado de grafos 36
v Ciclos hamiltonianos 44
v Atravesar un laberinto 52
v El recorrido del caballo de ajedrez 56
v El problema de la mochila 0-1 74
v Reconstrucción de puntos
a partir de las distancias 85
v Árboles de juego: tic-tac-toe 95
64
Fuerza bruta: = 4.426.165.368
8
– Restricciones explícitas:
Ci = {1,2,3,4,5,6,7,8}, 1=i=8
⇒ El espacio de soluciones consta de
88 8-tuplas (16.777.216 8-tuplas)
– Restricciones implícitas:
no puede haber dos reinas en la misma
columna ni en la misma diagonal
– En particular, se deduce que todas las soluciones
son permutaciones de la 8-tupla (1,2,3,4,5,6,7,8).
⇒ El espacio de soluciones se reduce de
88 8-tuplas (16.777.216) a 8! 8-tuplas (40.320)
1 2 3 4 5 6 7 8
1
2
3
4
5
6
7
8
x1 =1 x1 =4
x1 =2 x1 =3
2 18 34 50
x2 =2 x2 =4 x2 =1 x2 =4 x2 =1 x2 =4 x2 =1 x2 =3
x2 =3 x2 =3 x2 =2 x2 =2
3 8 13 19 24 29 35 40 45 51 56 61
x3 = 3 4 2 4 2 3 3 4 1 4 1 3 2 4 1 4 1 2 2 3 1 3 1 2
4 6 9 11 14 16 20 22 25 27 30 32 36 38 41 43 46 48 52 54 57 59 62 64
4 4 3 4 4 3 4 4 2 3 3 2
x4 = 2
3 2 2 3 1 1 2 1 2 1 1
5 7 10 12 15 17 21 23 26 28 31 33 37 39 42 44 47 49 53 55 58 60 63 65
v Esquema algorítmico:
algoritmo
algoritmo retroceso(ent
retroceso(ent k:entero;
k:entero;
entsal
entsal solución:vector[1..n]de
solución:vector[1..n]de elmto)
elmto)
{Pre:
{Pre: solución[1..k-1]
solución[1..k-1] es
es ‘prometedora’}
‘prometedora’}
variable
variable nodo:elmto
nodo:elmto
principio
principio
para
para todo
todo nodo
nodo en
en G(solución,1,k-1)
G(solución,1,k-1) hacer
hacer
solución[k]:=nodo;
solución[k]:=nodo;
si
si A(solución,1,k)
A(solución,1,k)
entonces
entonces
si
si R(solución,1,k)
R(solución,1,k)
entonces
entonces guardar(solución,1,k)
guardar(solución,1,k)
fsi;
fsi;
retroceso(k+1,solución)
retroceso(k+1,solución)
fsi
fsi
fpara
fpara
fin
fin
...
...
retroceso(1,solución);
retroceso(1,solución);
...
...
× ×
× × × × ×
x1 =1 x1 =2
× × × ×
2 18
(e) (f)
x2 =2 x2 =4 x2 =1 x2 =4
x2 =3 x2 =3
× × × 3 8 13 19 24 29
x3 = 2 4 2 3 1
9 11 14 16 30
(g)
x4 = 3 3
15 31
v De nuevo, en general:
– Backtracking =
v Variantes:
– Limitar el número de soluciones a una sola
añadiendo un parámetro booleano de salida que
indique si se ha encontrado una solución.
v Sobre la eficiencia:
– Depende de:
u el tiempo necesario para generar un
elemento solución[k],
u el número de elementos solución que
satisfacen las restricciones explícitas G,
u el tiempo de ejecución de los predicados
acotadores A, y
u el número de elementos solución[k] que
satisfacen los predicados A.
– Mejoras:
u Si se consigue que los predicados acotadores
reduzcan mucho el número de nodos
generados
(aunque un buen predicado acotador precisa
mucho tiempo de evaluación;
compromiso…)
– Si lo reducen a un solo nodo generado
(solución voraz): O(n) nodos a generar
en total
– En el peor caso, O(p(n)×2n) ó O(p(n)×n!),
con p(n) un polinomio
u Si es posible: reordenar las selecciones de
forma que |C1|<|C2|<⋅⋅⋅<|Cn|, y así cabe
esperar que se explorarán menos caminos.
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
Búsqueda con retroceso:
Introducción
m = 1 + m 1 + m 1 m 2 + m 1m 2m 3 +L
función
función estimación
estimación devuelve
devuelve entero
entero
variables
variables k,m,r,card:entero;
k,m,r,card:entero;
nodo:elmto;
nodo:elmto;
sol:vector[1..n]de
sol:vector[1..n]de elmtoelmto
principio
principio
k:=1;
k:=1; m:=0;
m:=0; r:=1;
r:=1;
repetir
repetir
card:=0;
card:=0;
para
para todo
todo nodo
nodo en
en G(sol,1,k-1)
G(sol,1,k-1) hacer
hacer
sol[k]:=nodo;
sol[k]:=nodo;
si
si A(sol,1,k)
A(sol,1,k)
entonces
entonces card:=card+1
card:=card+1
fsi
fsi
fpara;
fpara;
si card≠≠00
si card
entonces
entonces
r:=r*card;
r:=r*card;
m:=m+r;
m:=m+r;
sol[k]:=eleccAleat(G(sol,1,k-1));
sol[k]:=eleccAleat(G(sol,1,k-1));
k:=k+1
k:=k+1
fsi
fsi
hastaQue
hastaQue R(sol,1,k)
R(sol,1,k) or or (card=0);
(card=0);
devuelve
devuelve mm
fin
fin
v Representación de la información
Debe permitir interpretar fácilmente la solución:
x:vector[1..n]de entero;
{x[i]=columna de la reina en i-ésima fila}
funcion
funcion buenSitio(k:entero;
buenSitio(k:entero;
x:vector[1..n]de
x:vector[1..n]de entero)
entero)
devuelve
devuelve bool
bool
{devuelve
{devuelve verdad
verdad si
si yy sólo
sólo si
si se
se puede
puede colocar
colocar
una
una reina en la fila k y columna x[k], habiendo
reina en la fila k y columna x[k], habiendo
sido colocadas ya las k-1 reinas anteriores}
sido colocadas ya las k-1 reinas anteriores}
variables
variables i:entero;
i:entero; amenaza:bool
amenaza:bool
principio
principio
i:=1;
i:=1; amenaza:=falso;
amenaza:=falso;
mq
mq (i<k) and
(i<k) and not
not amenaza
amenaza hacer
hacer
si
si x[i]=x[k]
x[i]=x[k] or
or abs(x[i]-x[k])=abs(i-k)
abs(x[i]-x[k])=abs(i-k)
entonces
entonces amenaza:=verdad
amenaza:=verdad
sino
sino i:=i+1
i:=i+1
fsi
fsi
fmq;
fmq;
devuelve
devuelve not
not amenaza
amenaza
fin
fin
Versión recursiva:
algoritmo
algoritmo colocarReinas(ent
colocarReinas(ent k:entero;
k:entero;
entsal
entsal sol:vector[1..n]de entero)
sol:vector[1..n]de entero)
{sol[1..k-1]
{sol[1..k-1] están
están bien
bien colocadas}
colocadas}
variables
variables i:entero
i:entero
principio
principio
para
para i:=1
i:=1 hasta
hasta nn hacer
hacer
sol[k]:=i;
sol[k]:=i;
si
si buenSitio(k,sol)
buenSitio(k,sol)
entonces
entonces
si
si k=n
k=n
entonces
entonces escribir(sol)
escribir(sol)
sino
sino colocarReinas(k+1,sol)
colocarReinas(k+1,sol)
fsi
fsi
fsi
fsi
fpara
fpara
fin
fin
...
...
colocarReinas(1,sol);
colocarReinas(1,sol);
...
...
Versión iterativa:
algoritmo
algoritmo nReinas(ent
nReinas(ent n:entero)
n:entero)
variables
variables k:entero;
k:entero; x:vector[1..n]de
x:vector[1..n]de entero entero
principio
principio
x[1]:=0;
x[1]:=0; k:=1;
k:=1;
mq k>0 hacer
mq k>0 hacer {para{para frenar
frenar elel último
último retroceso}
retroceso}
x[k]:=x[k]+1;
x[k]:=x[k]+1;
mq x[k]≤≤nn and
mq x[k] and not
not buenSitio(k,x)
buenSitio(k,x) hacer hacer
x[k]:=x[k]+1
x[k]:=x[k]+1
fmq;
fmq;
si x[k]≤≤nn {se
si x[k] {se ha
ha encontrado
encontrado un un buen
buen sitio}
sitio}
entonces
entonces
si
si k=n
k=n {¿es
{¿es una
una solución
solución completa?}
completa?}
entonces
entonces
escribir(x)
escribir(x) {si: {si: escribirla}
escribirla}
sino
sino
k:=k+1;
k:=k+1;
x[k]:=0
x[k]:=0 {ir{ir aa la
la siguiente
siguiente fila}
fila}
fsi
fsi
sino
sino
k:=k-1
k:=k-1 {retroceso}
{retroceso}
fsi
fsi
fmq
fmq
fin
fin
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
El problema de las ocho reinas
(8,6,4,3,2)→1977 (8,5,3,2,2,1,1,1)→2329
( )
En este caso, la estimación es algo optimista pues
se puede comprobar que el número de nodos
explorados es 2057 y, por tanto, se recorre un 2’97%.
v Para n mayor:
v Novedad:
Recientemente se ha encontrado una
solución compacta para el problema
general de las n reinas en un tablero
n×n (excepto para n=2, n=3, n=8 y n=9):
(2k-1,k), 1≤k≤p
(2m,m+p), 1≤m≤p-1
u Si n es múltiplo de 3 y n≠3 y n≠9:
(2k,k), 1≤k≤p
(2m-1,m+p), 1≤m≤p
u Si n≡2 mód 3 y n≠2 y n≠8:
v Problema:
– Dados un conjunto W={w1,…,wn} de n números
positivos y otro número positivo M, se trata de
encontrar todos los subconjuntos de W cuya
suma es M.
de forma que:
u xi = 0 si wi no se elige y
u xi = 1 si wi se elige.
v Conclusión:
– Pueden existir varias formas de formular un
problema, con distintas representaciones de las
soluciones (aunque siempre verificando éstas un
conjunto de restricciones explícitas e implícitas).
x1 =1 x1 =4
x1 =2
x1 =3
2 3 4 5
x2 =3 x2 =4
x2 =2 x2 =4
x2 =3 x =4
2
6 7 8 9 10 11
x3 =3 x3 =4 x3 =4 x3 =4
12 13 14 15
x4 =4
16
x1 =1 x1 =0
2 3
x2 =1 x2 =0 x2 =1 x2 =0
18 19 4 5
x3 =1 x3 =0 x3 =1 x3 =0 x3 =1 x3 =0 x3 =1 x3 =0
26 27 20 21 12 13 6 7
x4 =0 x4 =0 x4 =0 x4 =0 x4 =0 x4 =0
x4 =0 x4 =0
x4 =1 x4 =1 x4 =1 x4 =1 x4 =1 x4 =1 x4 =1 x4 =1
30 31 28 29 24 25 22 23 16 17 14 15 10 11 8 9
– Función acotadora:
La tupla (x[1],…x[k]) sólo puede conducir a una
solución si:
k n
∑ w[i ] x[ i ] + ∑w [i ] ≥ M
i =1 i =k +1
( )
Bk x[1],…,x[k ] = verdad si y sólo si
k n
∑ w [i ] x[ i ] + ∑ w [ i ] ≥ M ∧
i =1 i =k +1
k
∧ ∑ w [ i ] x[ i ] + w [ k + 1] ≤ M
i =1
algoritmo
algoritmo sumasub(ent
sumasub(ent s,k,r:entero)
s,k,r:entero)
{Encuentra
{Encuentra todos
todos los
los subconjuntos
subconjuntos deldel vector
vector
global
global ww cuya
cuya suma
suma es
es M.
M.
Los
Los valores de x[j], que es
valores de x[j], que es otro
otro vector
vector global,
global,
1≤j<k ya han sido calculados.
1≤j<k ya han sido calculados.
k -1 n
s=∑ j=1 w[j]*x[j];
s= r=∑ j=k w[j].
w[j]*x[j]; r= w[j].
Los
Los w[j]
w[j] están
están en
en orden
ordennno
no decreciente.
decreciente.
Se asume que w[1]≤M y ∑ i=1 w[i]≥M.}
Se asume que w[1]≤M y w[i]≥M.}
principio
principio
{Generación
{Generación del
del hijo
hijo izquierdo.
izquierdo.
Nótese que s+w[k]≤M porqueBk − 1 (x[ 1] ,…,x[k - 1]) =verdad }}
Nótese que s+w[k]≤M porque
x[k]:=1;
x[k]:=1;
si
si s+w[k]=M
s+w[k]=M {se
{se ha
ha encontrado
encontrado un un subconjunto}
subconjunto}
entonces
entonces escribir(x[1..k])
escribir(x[1..k])
sino
sino
si s+w[k]+w[k+1]≤≤MM
si s+w[k]+w[k+1]
entonces {Bk (x[ 1] ,…,x [k ]) =verdad}
entonces
sumasub(s+w[k],k+1,r-w[k])
sumasub(s+w[k],k+1,r-w[k])
fsi
fsi
fsi
fsi
...
...
...
...
{Generación
{Generación del
del hijo
hijo derecho
derecho yy evaluación deBk }}
evaluación de
si (s+r-w[k]≥≥M)
si (s+r-w[k] M) and (s+w[k+1]≤≤M)
and (s+w[k+1] M) {Bk =verdad}
entonces
entonces
x[k]:=0;
x[k]:=0;
sumasub(s,k+1,r-w[k])
sumasub(s,k+1,r-w[k])
fsi
fsi
fin
fin
0,1,73
x[1]=1
5,2,68 0,2,68
x[2]=1 x[2]=0
v Problema de decisión:
– Dados un grafo G y un número entero positivo
m, ¿es G m-coloreable?
– Es decir, ¿se puede pintar con colores los nodos
de G de modo que no haya dos vértices
adyacentes con el mismo color y se usen sólo m
colores?
v Problema de optimización:
– Dado un grafo G, ¿cuál es su número cromático?
– Es decir, ¿cuál es el menor número m de colores
con el que se puede colorear G?
1
4 5
2 2 3
1
3
4
5
tipo
tipo grafo
grafo == vector[1..n,1..n]
vector[1..n,1..n] de
de bool
bool
tipo
tipo color
color == 0..m
0..m
tipo
tipo sol
sol == vector[1..n]
vector[1..n] de
de color
color
x[1]=1 x[1]=3
x[1]=2
x[2]=1 x[2]=3
x[2]=2
x[3]=
x[3]=1
3
x[3]
=2
Grado m y altura n.
Cada nodo de nivel i tiene m hijos que
corresponden a las m posibles asignaciones a x[i],
1≤i≤n.
algoritmo
algoritmo siguienteValor(entsal
siguienteValor(entsal x:sol;
x:sol;
ent
ent k:entero)
k:entero)
{x[1]…x[k-1]
{x[1]…x[k-1] tienen
tienen colores
colores asociados
asociados de de forma
forma
que todos los vértice adyacentes tienen
que todos los vértice adyacentes tienen distinto distinto
color.
color.
x[k]
x[k] tiene
tiene elel anterior
anterior color
color para
para el
el que
que se
se ha
ha
probado (0 si no se ha probado con ninguno).
probado (0 si no se ha probado con ninguno).
Se
Se calcula
calcula el el siguiente
siguiente color
color para
para x[k]
x[k]
diferente
diferente del de todos los vértices adyacentes
del de todos los vértices adyacentes
aa kk (0
(0 si
si no
no hay
hay ninguno).}
ninguno).}
variables
variables encontrado:booleano;
encontrado:booleano; j:entero
j:entero
principio
principio
repetir
repetir
x[k]:=(x[k]+1)
x[k]:=(x[k]+1) mod mod (m+1);
(m+1); {siguiente
{siguiente color}
color}
si x[k]≠≠00
si x[k]
entonces
entonces
encontrado:=verdad;
encontrado:=verdad;
j:=1;
j:=1;
mq
mq (j≤n)
(j≤n) and
and encontrado
encontrado hacer
hacer
si g[k,j] and (x[k]=x[j])
si g[k,j] and (x[k]=x[j])
entonces
entonces encontrado:=falso
encontrado:=falso
sino
sino j:=j+1
j:=j+1
fsi
fsi
fmq
fmq
fsi
fsi
hastaQue
hastaQue (x[k]=0)
(x[k]=0) or or encontrado
encontrado
fin
fin
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
Coloreado de grafos
∑ mi n = n (m n + 1 − 1 ) (m − 1)= O (nm n )
n
i= 1
u vi∈V, i=1,…,n+1,
u (vi,vi+1)∈A, i=1,…,n,
u v1=vn+1,
v Ejemplos:
1 2 3 4
8 7 6 5
Hamiltoniano: 1-2-8-7-6-5-4-3-1
1 2 3
5 4
tipo
tipo grafo
grafo == vector[1..n,1..n]
vector[1..n,1..n] de
de bool
bool
tipo
tipo sol
sol == vector[1..n]
vector[1..n] de
de 1..n
1..n
algoritmo
algoritmo siguienteValor(entsal
siguienteValor(entsal x:sol;
x:sol;
ent
ent k:entero)
k:entero)
{x[1],…,x[k-1]
{x[1],…,x[k-1] eses un
un camino
camino de de k-1
k-1 vértices
vértices
distintos.
distintos.
Si
Si x[k]=0,
x[k]=0, nono se
se ha
ha asignado
asignado ningún
ningún vértice
vértice
todavía
todavía aa x[k].
x[k].
Al
Al terminar, x[k]
terminar, x[k] toma
toma elel valor
valor del
del siguiente
siguiente
(en orden ascendente) vértice
(en orden ascendente) vértice tal que:tal que:
(1)
(1) no
no aparece
aparece yaya en
en x[1],…,x[k-1],
x[1],…,x[k-1], yy
(2)
(2) está
está conectado
conectado porpor unun arco
arco aa x[k-1].
x[k-1].
Además,
Además, sisi k=n,
k=n, se
se debe
debe exigir
exigir aa x[k]
x[k] que:
que:
(3)
(3) está
está conectado
conectado porpor unun arco
arco aa x[1].
x[1].
Si no hay tal vértice, x[k]=0.}
Si no hay tal vértice, x[k]=0.}
...
...
algoritmo
algoritmo hamiltoniano(ent
hamiltoniano(ent k:entero;
k:entero;
entsal
entsal x:sol)
x:sol)
{Se
{Se usa
usa una
una variable
variable global
global gg dede tipo
tipo grafo.
grafo.
Cálculo
Cálculo de los ciclos hamiltonianos de un
de los ciclos hamiltonianos de un grafo
grafo
mediante búsqueda con retroceso.
mediante búsqueda con retroceso.
En
En xx se
se tiene
tiene la
la parte
parte de
de la
la solución
solución ya ya calculada
calculada
(es
(es decir,
decir, hasta
hasta x[k-1])
x[k-1]) yy kk es
es el
el índice
índice del
del
siguiente
siguiente vértice
vértice del
del ciclo
ciclo que
que sese va
va aa asignar.}
asignar.}
principio
principio
repetir
repetir
{generar
{generar todos
todos los
los valores
valores ‘legales’
‘legales’ para
para x[k]}
x[k]}
siguienteValor(x,k);
siguienteValor(x,k);
si x[k]≠≠00
si x[k]
entonces
entonces
si
si k=n
k=n
entonces
entonces
escribir(x,’1’)
escribir(x,’1’)
sino
sino hamiltoniano(k+1,x)
hamiltoniano(k+1,x)
fsi
fsi
fsi
fsi
hastaQue
hastaQue x[k]=0
x[k]=0
fin
fin
v Problema:
– Nos encontramos en una entrada de un laberinto
y debemos intentar atravesarlo.
v Estructura de datos:
tipos
tipos
casilla
casilla == (libre,pared,camino,imposible)
(libre,pared,camino,imposible)
laberinto
laberinto = vector[1..n,1..n]
= vector[1..n,1..n] de
de casilla
casilla
algoritmo
algoritmo ensayar(ent
ensayar(ent x,y:entero;
x,y:entero;
entsal
entsal lab:laberinto;
lab:laberinto;
sal
sal encontrado:booleano)
encontrado:booleano)
principio
principio
si (x<1)∨∨(x>n)
si (x<1) (x>n)∨∨(y<1)
(y<1)∨∨(y>n)
(y>n)
entonces
entonces {posición
{posición fuera
fuera del
del laberinto}
laberinto}
encontrado:=falso
encontrado:=falso
sino
sino
si lab[x,y]≠≠libre
si lab[x,y] libre
entonces encontrado:=falso
entonces encontrado:=falso
sino
sino
...
...
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
Atravesar un laberinto
...
...
lab[x,y]:=camino;
lab[x,y]:=camino;
si (x=n)∧∧(y=n)
si (x=n) (y=n)
entonces
entonces {se{se ha
ha encontrado
encontrado una
una soluc.}
soluc.}
encontrado:=verdad
encontrado:=verdad
sino
sino
ensayar(x+1,y,lab,encontrado);
ensayar(x+1,y,lab,encontrado);
si
si not
not encontrado
encontrado
entonces
entonces
ensayar(x,y+1,lab,encontrado)
ensayar(x,y+1,lab,encontrado)
fsi;
fsi;
si
si not
not encontrado
encontrado
entonces
entonces
ensayar(x-1,y,lab,encontrado)
ensayar(x-1,y,lab,encontrado)
fsi;
fsi;
si
si not
not encontrado
encontrado
entonces
entonces
ensayar(x,y-1,lab,encontrado)
ensayar(x,y-1,lab,encontrado)
fsi;
fsi;
si
si not
not encontrado
encontrado
entonces
entonces
lab[x,y]:=imposible
lab[x,y]:=imposible
fsi
fsi
fsi
fsi
fsi
fsi
fsi
fsi
fin
fin
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
El recorrido del caballo de
ajedrez
v Problema:
1 2 3 4 5 6 7 8
1
2
3
4
5
6
7
8
– Movimientos “legales”:
6 7
5 8
4 1
3 2
variables
variables dx,dy:vector[1..8]
dx,dy:vector[1..8] de
de entero
entero
...
...
dx:=[2,1,-1,-2,-2,-1,1,2]
dx:=[2,1,-1,-2,-2,-1,1,2]
dy:=[1,2,2,1,-1,-2,-2,-1]
dy:=[1,2,2,1,-1,-2,-2,-1]
variable
variable
tab:vector[1..n,1..n]
tab:vector[1..n,1..n] de
de entero
entero
...
...
si
si éxito
éxito
entonces
entonces
para
para i:=1
i:=1 hasta
hasta nn hacer
hacer
para
para j:=1
j:=1 hasta
hasta nn hacer
hacer
escribir(tab[i,j]);
escribir(tab[i,j]);
fpara;
fpara;
escribirLínea
escribirLínea
fpara
fpara
sino
sino
escribir(‘No
escribir(‘No hay
hay solución’)
solución’)
fsi
fsi
fin
fin
v Resultado de la ejecución:
Introduce i inicial: 1
Introduce j inicial: 1
1 60 39 34 31 18 9 64
38 35 32 61 10 63 30 17
59 2 37 40 33 28 19 8
36 49 42 27 62 11 16 29
43 58 3 50 41 24 7 20
48 51 46 55 26 21 12 15
57 44 53 4 23 14 25 6
52 47 56 45 54 5 22 13
función
función accesibles(ent
accesibles(ent x,y:entero)
x,y:entero)
devuelve
devuelve entero
entero
{Devuelve
{Devuelve el
el número
número de
de escaques
escaques no
no visitados
visitados
accesibles
accesibles desde
desde x,y.}
x,y.}
variables
variables k,u,v,num:entero
k,u,v,num:entero
principio
principio
num:=0;
num:=0;
para
para k:=1
k:=1 hasta
hasta 88 hacer
hacer
u:=x+dx[k];
u:=x+dx[k];
v:=y+dy[k];
v:=y+dy[k];
si (1≤≤u)
si (1 u)∧∧(u
(u≤≤n)
n)∧∧(1
(1≤≤v)
v)∧∧(v
(v≤≤n)
n)
entonces
entonces
si
si tab[u,v]=0
tab[u,v]=0
entonces
entonces num:=num+1
num:=num+1
fsi
fsi
fsi
fsi
fpara
fpara
devuelve
devuelve num num
fin
fin
...
...
si
si not
not parar
parar
entonces
entonces
para
para i:=1
i:=1 hasta
hasta nn hacer
hacer
para
para j:=1
j:=1 hasta
hasta nn hacer
hacer
escribir(tab[i,j])
escribir(tab[i,j])
fpara;
fpara;
escribirLínea
escribirLínea
fpara
fpara
sino
sino
escribir(‘No
escribir(‘No encuentro
encuentro solución’)
solución’)
fsi
fsi
fin
fin
v Resultado de la ejecución:
Introduce x inicial: 1
Introduce y inicial: 1
1 34 3 18 49 32 13 16
4 19 56 33 14 17 50 31
57 2 35 48 55 52 15 12
20 5 60 53 36 47 30 51
41 58 37 46 61 54 11 26
6 21 42 59 38 27 64 29
43 40 23 8 45 62 25 10
22 7 44 39 24 9 28 63
Introduce i inicial: 1
Introduce j inicial: 3
25 14 1 8 19
4 9 18 13 2
15 24 3 20 7
10 5 22 17 12
23 16 11 6 21
v Solución:
– Mejorar el algoritmo de búsquedad con retroceso
cambiando el orden de ensayo de las casillas
accesibles desde una dada.
...
...
{se
{se ensaya
ensaya por
por orden
orden de
de menor
menor aa mayor
mayor nº
nº de
de
casillas accesibles no visitadas}
casillas accesibles no visitadas}
éxito:=falso;
éxito:=falso;
mq
mq not
not esVacía(cola)
esVacía(cola) and
and not
not éxito
éxito hacer
hacer
m:=min(cola);
m:=min(cola); eliminarMin(cola);
eliminarMin(cola);
k:=m.valor;
k:=m.valor;
u:=x+dx[k];
u:=x+dx[k]; v:=y+dy[k];
v:=y+dy[k];
tab[u,v]:=i;
tab[u,v]:=i;
si
si i<n*n
i<n*n
entonces
entonces
ensaya(i+1,u,v,éxito);
ensaya(i+1,u,v,éxito);
si
si not
not éxito
éxito
entonces
entonces tab[u,v]:=0
tab[u,v]:=0
fsi
fsi
sino
sino éxito:=verdad
éxito:=verdad
fsi
fsi
fmq
fmq
fin
fin
Introduce i inicial: 1
Introduce j inicial: 3
23 6 1 16 21
12 17 22 7 2
5 24 11 20 15
10 13 18 3 8
25 4 9 14 19
v Recordar…
– Se tienen n objetos y una mochila.
– El objeto i tiene peso pi y la inclusión del objeto i
en la mochila produce un beneficio bi.
– El objetivo es llenar la mochila, de capacidad C,
de manera que se maximice el beneficio.
maximizar ∑ bixi
1≤i ≤n
sujeto a ∑ pixi ≤ C
1≤i ≤n
v Espacio de soluciones:
– 2n modos de asignar los valores 0 ó 1 a las xi.
– Dos formas de representar la solución: tuplas de
tamaño fijo o variable.
x1 =1 x1 =4
x1 =2
x1 =3
2 10 14 16
x2 =3 x2 =4
x2 =2 x2 =4
x2 =3 x =4
2
3 7 9 11 13 15
x3 =3 x3 =4 x3 =4 x3 =4
4 6 8 12
x4 =4
x1 =0 x1 =1
2 17
x2 =0 x2 =1 x2 =0 x2 =1
3 10 18 25
x3 =0 x3 =1 x3 =0 x3 =1 x3 =0 x3 =1 x3 =0 x3 =1
4 7 11 14 19 22 26 29
x4 =1 x4 =1 x4 =1 x4 =1 x4 =1 x4 =1
x4 =1 x4 =1
x4 =0 x4 =0 x4 =0 x4 =0 x4 =0 x4 =0 x4 =0 x4 =0
5 6 8 9 12 13 15 16 20 21 23 24 27 28 30 31
constante
constante n=...
n=... {número
{número de
de objetos}
objetos}
tipo
tipo vectReal=vector[1..n]
vectReal=vector[1..n] de de real
real
{Pre: ∀i∈1..n:peso[i]>0 ∧
∀i∈1..n-1:benef[i]/peso[i]≥benef[i+1]/peso[i+1]}
función
función cota(benef,peso:vectReal;
cota(benef,peso:vectReal;
cap,ben:real;
cap,ben:real; obj:entero)
obj:entero)
devuelve
devuelve real
real
{cap=capacidad
{cap=capacidad aún
aún libre
libre de
de la
la mochila;
mochila;
ben=beneficio
ben=beneficio actual;
actual;
obj=índice
obj=índice del
del primer
primer objeto
objeto aa considerar}
considerar}
principio
principio
si
si obj>n
obj>n or
or cap=0.0
cap=0.0
entonces
entonces devuelve
devuelve ben
ben
sino
sino
si
si peso[obj]>cap
peso[obj]>cap
entonces
entonces
dev
dev ben+cap/peso[obj]*benef[obj]
ben+cap/peso[obj]*benef[obj]
sino
sino
dev
dev cota(benef,peso,cap-peso[obj],
cota(benef,peso,cap-peso[obj],
ben+benef[obj],obj+1)
ben+benef[obj],obj+1)
fsi
fsi
fsi
fsi
fin
fin
tipo
tipo solución=vector[1..n]
solución=vector[1..n] de
de 0..1
0..1
{variables
{variables globales:
globales:
benef,peso:vectReal;
benef,peso:vectReal; cap:real}
cap:real}
algoritmo
algoritmo búsqueda(ent
búsqueda(ent solAct:solución;
solAct:solución;
ent
ent benAct,pesAct:real;
benAct,pesAct:real;
ent
ent obj:entero;
obj:entero;
e/s sol:solución;
e/s sol:solución;
e/s
e/s ben:real)
ben:real)
variable
variable decisión:0..1
decisión:0..1
principio
principio
para
para decisión:=0
decisión:=0 hasta
hasta 11 hacer
hacer
solAct[obj]:=decisión;
solAct[obj]:=decisión;
benAct:=benAct+decisión*benef[obj];
benAct:=benAct+decisión*benef[obj];
pesAct:=pesAct+decisión*peso[obj];
pesAct:=pesAct+decisión*peso[obj];
si pesAct≤≤cap
si pesAct cap and
and ben<cota(benef,peso,
ben<cota(benef,peso,
cap-pesAct,benAct,obj+1)
cap-pesAct,benAct,obj+1) entonces
entonces
si obj=n
si obj=n
entonces
entonces si si benAct>ben
benAct>ben entonces
entonces
sol:=solAct;
sol:=solAct; ben:=benAct
ben:=benAct
fsi
fsi
sino
sino búsqueda(solAct,benAct,pesAct,
búsqueda(solAct,benAct,pesAct,
obj+1,sol,ben)
obj+1,sol,ben)
fsi
fsi
fsi
fsi
fpara
fpara
fin
fin
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
El problema de la mochila 0-1
algoritmo
algoritmo mochila01(ent
mochila01(ent benef,peso:vectReal;
benef,peso:vectReal;
ent
ent cap:real;
cap:real;
sal
sal sol:solución;
sol:solución;
sal
sal ben:real)
ben:real)
variables
variables obj:entero;
obj:entero; solAct:solución
solAct:solución
principio
principio
para
para obj:=1
obj:=1 hasta
hasta nn hacer
hacer
solAct[obj]:=0;
solAct[obj]:=0; sol[obj]:=0
sol[obj]:=0
fpara;
fpara;
ben:=0.0;
ben:=0.0;
búsqueda(solAct,0.0,0.0,1,sol,ben)
búsqueda(solAct,0.0,0.0,1,sol,ben)
fin
fin
v Ejemplo:
– benef=(11,21,31,33,43,53,55,65)
– peso=(1,11,21,23,33,43,45,55)
– cap=110
– n=8
164.88
1 0
1
11 155.11
1 0
12 157.44
32
1 0
33 159.76
63
1 0 1 0
56 160.22 35
96 65 154.88
1 0 1 0 1 0
89 162.44 66 68 157.11
139 106 108
0 1 0 1 0 157.55 0
164.66 99 109 159.79 159.33
149 159
0 0 1161.63 0 0 0
163.81 101 158 157.63
151
162 160.18
0 0 0 0
139
ben=159
149 151 159 sol=(1,1,1,0,1,1,0,0)
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
El problema de la mochila 0-1
con 0 ≤ xi ≤ 1, 1 ≤ i ≤ n
uSi la solución obtenida es entera (0-1),
también es óptima para el problema 0-1.
u Si no es entera, existe exactamente un xi tal
que 0<xi<1.
Se parte el espacio de soluciones en dos
subespacios: en uno (subárbol izquierdo)
xi=0 y en otro (subárbol derecho) xi=1.
– En general, en cada nodo del árbol, se usa el
algoritmo voraz para resolver el problema (*) con
las restricciones añadidas correspondientes a las
asignaciones ya realizadas a lo largo del camino
desde la raíz al nodo.
u Si la solución es entera, ya se tiene el óptimo
para ese nodo.
u Si no lo es, existe exactamente un xi tal que
0<xi<1, etc.
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
Reconstrucción de puntos a
partir de las distancias
v Veamos un ejemplo:
D={1,2,2,2,3,3,3,4,5,5,5,6,7,8,10}
x1=0 x6=10
D={1,2,2,2,3,3,3,4,5,5,5,6,7,8}
Retroceso...
x1=0,x6=10
x5=8
x4=7** x2=3
x3=5
algoritmo
algoritmo reconstruir(ent
reconstruir(ent D:saco;
D:saco;
sal x:sol;
sal x:sol;
sal
sal éxito:booleano)
éxito:booleano)
{Pre:
{Pre: |D|=n(n-1)/2}
|D|=n(n-1)/2}
principio
principio
éxito:=falso;
éxito:=falso;
x[1]:=0;
x[1]:=0;
x[n]:=máximo(D);
x[n]:=máximo(D);
eliminarMáx(D);
eliminarMáx(D);
x[n-1]:=máximo(D);
x[n-1]:=máximo(D);
eliminarMáx(D);
eliminarMáx(D);
si x[n]-x[n-1]∈∈DD
si x[n]-x[n-1]
entonces
entonces
eliminar(x[n]-x[n-1],D);
eliminar(x[n]-x[n-1],D);
colocar(x,D,2,n-2,éxito)
colocar(x,D,2,n-2,éxito)
sino
sino
éxito:=falso
éxito:=falso
fsi
fsi
fin
fin
v Análisis de la eficiencia:
el coste es O(n2log n)
Sin embargo:
u “configuración ganadora”,
u “configuración perdedora” y
u “configuración empatadora o nula”.
– Interpretación:
•••
• • •
• • •
• • •
función de
yo yo utilidad “ganadora”
nivel 6 yoél 1
mueve “yo” él él función de
utilidad “perdedora”
yo yo yo yo yo yo yo
nivel 7 yo él 1 yo yoél -1 yo él 0
mueve “él”
él él él él él yo él
GANA “yo”
yo él yo yo yo yo él yo yo yo
nivel 8 yo yo él 0 yo yo él -1 yo él 0 él yo él 1
mueve “yo” él él él él él él yo él él yo él
GANA “él”
yo él yo yo él yo yo yo yo
nivel 9 yo yo él 0 yo yo él 0 él yo él 1
él yo él él yo él él yo él
v Cálculo de la utilidad:
– Se da valor, en primer lugar, a las hojas:
u la utilidad en una hoja vale 1, 0 ó -1 si la
configuración del juego corresponde a una
victoria, empate o derrota, respectivamente,
del jugador por el que hemos tomado
partido (“yo”).
– Los valores de la función de utilidad se
propagan hacia arriba del árbol de acuerdo a la
siguiente regla (estrategia minimax):
u si un nodo corresponde a una configuración
del juego en la que juega “yo” (nivel 0 ó
par), se supone que ese jugador hará la
mejor jugada de entre las posibles y, por
tanto, el valor de la función de utilidad en la
configuración actual coincide con el valor de
esa función en la configuración de la mejor
jugada posible (para “yo”) que se puede
realizar desde la actual (nodo max);
u si un nodo corresponde a una configuración
del juego en la que juega “él” (nivel impar
del árbol), se supone que ese jugador hará la
mejor jugada de entre las posibles y, por
tanto, el valor de la función de utilidad en la
configuración actual coincide con el valor de
esa función en la configuración de la peor
jugada posible (para “yo”) (nodo min).
J. Campos - C.P.S. Esquemas algorítmicos - Búsqueda con retroceso
Árboles de juego: tic-tac-toe
algoritmo
algoritmo juegaElComputador(e/s
juegaElComputador(e/s c:config)
c:config)
{c
{c es
es una
una configuración
configuración nono final;
final; el
el algoritmo
algoritmo
realiza
realiza lala mejor
mejor jugada
jugada posible
posible aa partir
partir de
de c,
c,
la comunica al usuario y actualiza
la comunica al usuario y actualiza c} c}
variables
variables maxUtilidad,laUtilidad:entero;
maxUtilidad,laUtilidad:entero;
i:1..maxEntero;
i:1..maxEntero;
mejorJugada,unaJugada:config
mejorJugada,unaJugada:config
principio
principio
i:=1;
i:=1;
{cálculo
{cálculo de
de la
la 1ª
1ª config.
config. accesible
accesible desde
desde c}
c}
jugada(c,i,unaJugada);
jugada(c,i,unaJugada);
mejorJugada:=unaJugada;
mejorJugada:=unaJugada;
maxUtilidad:=utilidad(mejorJugada,falso);
maxUtilidad:=utilidad(mejorJugada,falso);
{"falso"
{"falso" indica
indica que
que cuando
cuando la
la configuración
configuración
sea
sea "mejorJugada",
"mejorJugada", nono juego
juego yo}
yo}
mq
mq not
not esLaUltimaJugada(c,i)
esLaUltimaJugada(c,i) hacer
hacer
i:=i+1;
i:=i+1;
jugada(c,i,unaJugada);
jugada(c,i,unaJugada);
laUtilidad:=utilidad(unaJugada,falso);
laUtilidad:=utilidad(unaJugada,falso);
si
si laUtilidad>maxUtilidad
laUtilidad>maxUtilidad entonces
entonces
mejorJugada:=unaJugada;
mejorJugada:=unaJugada;
maxUtilidad:=laUtilidad
maxUtilidad:=laUtilidad
fsi
fsi
fmq;
fmq;
comunicaAlUsuario(mejorJugada);
comunicaAlUsuario(mejorJugada);
c:=mejorJugada
c:=mejorJugada
fin
fin
algoritmo
algoritmo jugada(ent
jugada(ent c:config;
c:config;
ent
ent i:1..maxEntero;
i:1..maxEntero;
sal
sal unaJugada:config)
unaJugada:config)
{Pre:
{Pre: cc admite
admite al
al menos
menos ii jugadas
jugadas diferentes.}
diferentes.}
{Post:
{Post: unaJugada es la i-ésima jugada posible
unaJugada es la i-ésima jugada posible
desde c.}
desde c.}
...
...
algoritmo
algoritmo esLaÚltimaJug(ent
esLaÚltimaJug(ent c:config;
c:config;
ent
ent i:0..maxEntero)
i:0..maxEntero)
devuelve
devuelve booleano
booleano
{Devuelve
{Devuelve verdad
verdad si
si yy sólo
sólo si
si cc admite
admite
exactamente i jugadas diferentes.}
exactamente i jugadas diferentes.}
...
...
algoritmo
algoritmo comunicaAlUsuario(ent
comunicaAlUsuario(ent c:config)
c:config)
{Muestra
{Muestra en
en pantalla
pantalla la
la configuración
configuración c.}
c.}
...
...
algoritmo
algoritmo utilidadFinal(ent
utilidadFinal(ent c:config)
c:config)
devuelve
devuelve entero
entero
{Pre:
{Pre: cc es
es una
una configuración
configuración final
final del
del juego.}
juego.}
{Post:
{Post: devuelve
devuelve la la utilidad
utilidad de
de c.}
c.}
...
...
algoritmo
algoritmo utilidad(ent
utilidad(ent c:config;
c:config;
ent
ent juegoYo:booleano)
juegoYo:booleano)
devuelve
devuelve entero
entero
{Calcula
{Calcula la
la utilidad
utilidad de
de cc teniendo
teniendo en
en cuenta
cuenta
quién juega.}
quién juega.}
variables
variables laUtilidad:entero;
laUtilidad:entero;
i:1..maxEntero;
i:1..maxEntero;
unaJugada:config
unaJugada:config
principio
principio
si
si esLaUltimaJug(c,0)
esLaUltimaJug(c,0)
entonces
entonces
devuelve
devuelve utilidadFinal(c)
utilidadFinal(c)
sino
sino
i:=1;
i:=1;
jugada(c,i,unaJugada);
jugada(c,i,unaJugada);
laUtilidad:=
laUtilidad:=
utilidad(unaJugada,not
utilidad(unaJugada,not juegoYo);
juegoYo);
...
...
...
...
mq
mq not
not esLaUltimaJug(c,i)
esLaUltimaJug(c,i) hacer
hacer
i:=i+1;
i:=i+1;
jugada(c,i,unaJugada);
jugada(c,i,unaJugada);
si
si juegoYo
juegoYo
entonces
entonces
laUtilidad:=
laUtilidad:=
max(laUtilidad,
max(laUtilidad,
utilidad(unaJugada,falso))
utilidad(unaJugada,falso))
sino
sino
laUtilidad:=
laUtilidad:=
min(laUtilidad,
min(laUtilidad,
utilidad(unaJugada,verdad))
utilidad(unaJugada,verdad))
fsi
fsi
fmq;
fmq;
devuelve
devuelve laUtilidad
laUtilidad
fsi
fsi
fin
fin
v Poda α:
d
15
v Poda β:
d
68
v Resultados prácticos: