Aquesta pàgina es genera automàticament a partir de la presentació MARP
3.2-busqueda-marp.md. No l’edites directament.
Busqueda en espais d’estats
Models d’intel·ligència artificial

Busqueda
- Fonamental en molts dominis
- Jocs, Planificació…
- Funciona molt bé en altres tipus de problemes
- Diagnòstic, Control, Aprenentatge, …
- És una tècnica molt general
- Podem aplicar-la a problemes sense solució específica
- Molt útil per aproximar
- Les tècniques de cerca són la base de molts sistemes intel·ligents
Busqueda en espais d’estats
- Els problemes de búsqueda tindran
- Un estat inicial
- Una funció de succesió
- Defineix els estats successors d’un estat i el cost per arribar a aquests estats
- Un estat final
- Una solució és una seqüència d’estats (un plà) que ens porten de l’estat inicial a l’estat final
Exemple: Viatjar per Romania
- Espai d’estats: Ciutats
- Funcio de succesió: Carreteres. Cost: Distància
- Estat inicial: Arad
- Comprovar si un estat és final: Estat = Bucharest
- Solució: Seqüència de ciutats que ens porten d’Arad a Bucharest

Exemple: Botelles d’aigua (I)
Tenim dues botelles d’aigua, una de 4 litres i una altra de 3 litres. Volem obtenir 2 litres d’aigua. Podem omplir les botelles, buidar-les o trasvasar l’aigua d’una a l’altra.
- Espai d’estats: Estat de les botelles
- Funcio de succesió: Operacions de buidar, omplir i trasvasar
- Estat inicial: (0,0)
- Comprovar si un estat és final: Estat = (2,0)
- Solució: Seqüència d’operacions que ens porten de (0,0) a (2,0)
Exemple: Botelles d’aigua (II)
Observacions
- Tal com està formulat el problema, no poden haver-hi estats no enters.
- Alguns estats són impossibles d’aconseguir. Ex: (1, 2)
- Algunes accions no produeixen canvis.
- Ex:
(0,0) + buidar(4) = (0,0)
- Ex:
Exemple: Puzzle 8 (I)
Tenim un tauler de 3x3 amb 8 peces numerades del 1 al 8 i un espai buit. Volem moure les peces per aconseguir l’estat final.
- Espai d’estats: -
- Funcio de succesió: -
- Estat inicial: -
- Comprovar si un estat és final: -
- Solució: -

Exemple: Puzzle 8 (II)
- Espai d’estats: Les diferents posicions de les peces. Quantes?
- Funcio de succesió: Podem moure la peça buida en les 4 direccions. Podem sempre fer els 4?
- Estat inicial: P.e. el de la figura anterior
- Comprovar si un estat és final: Verificar que les peces estan a la posició correcta.
- Solució: Seqüència de moviments que ens porten a l’estat final

Exemple: Puzzle 8 (III)
Observacions
- El nombre d’estats és molt gran: $9! = 362.880$ estats
- Solament quan la peça buida està al centre del tauler podem fer els 4 moviments
- No tots els estats tenen solució
- Hi ha moltes solucions
- Quina és la millor?
Situacions més complicades
- En els exemples anteriors, de cada estat coneixíem
- Els estats successors
- El cost de cada estat successor
- En altres problemes els resultat de cada acció és incert
- Veurem técniques per tractar algunes d’aquestes situacions
- Métodes probabilístics: assignar probabilitats als estats successors
- Métodes de cerca adversarial: els estats successors són determinats per un oponent
Representació dels problemes de cerca
Arbres de cerca
- Els problemes de cerca es poden representar com un arbre
- Els nodes són els estats
- Les arestes són les accions
- Els costos són els pesos de les arestes
- Podem aplicar algorismes de cerca de camins mínims
- L’espai de cerca ha de ser finit
Exemple: Viatjar per Romania

- Els nodes ja visitats es mostren en gris
- Els oberts en blanc i els encara per visitar en linees discontínues.
Algorismes de cerca

Definició
- Els algorismes de cerca són algorismes de propòsit general
- Poden ser aplicats a qualsevol problema de cerca
- Els problemes de cerca són un cas particular dels problemes de camins mínims
- Sortida:
- Una serie d’accions que ens porten de l’estat inicial a l’estat final
- El resultat pot ser una solució òptima en cost, óptima en temps o no tindre cap tipus de garantia d’optimalitat.
Funcionament general
- Tindrem una llista d’estats coneguts pero per visitar anomenada frontera. Inicialment la frontera conté l’estat inicial.
- En cada iteració, agafarem un estat de la frontera, aplicarem la funció de succesió i afegirem els nous estats a la frontera.
- Si l’estat és final, hem acabat.
- Si la frontera està buida, no hi ha solució.
- Per cada estat anotarem el seu pare, per poder reconstruir la solució.
- En cada iteració, podem aplicar una estratègia per decidir quin estat de la frontera agafem.
Exemple de funcionament (Alternativa I)
- Frontera: {Arad}. Objectiu: Bucharest
- Obrim Arad: {Z<A>, T<A>, S<A>},
- Obrim Sibiu: {Z<A>, T<A>, A<S,A>, O<S,A>, F<S,A>, R<S,A>}
-
Obrim Fagaras: {Z<A>, T<A>, A<S,A>, O<S,A>, R<S,A>, S<F,S,A>, B<F,S,A>}

- Tenim la solució en la frontera. Cost: 140+99+211 = 450
Exemple de funcionament (Alternativa II)

- Frontera: {Arad}. Objectiu: Bucharest
- Obrim Arad: {Z<A>, T<A>, S<A>},
- Obrim Sibiu: {Z<A>, T<A>, A<S,A>, O<S,A>, F<S,A>, R<S,A>}
- Obrim R.V: {Z<A>, T<A>, A<S,A>, O<S,A>, R<S,A>, S<R,S,A>, P<R,S,A>, C<R,S,A>}
- Obrim Pitesti: {Z<A>, T<A>, A<S,A>, O<S,A>, R<S,A>, S<R,S,A>, P<R,S,A>, C<R,S,A>, R<P,R,S,A>, C<P,R,S,A>, B<P,R,S,A>}
- Tenim la solució en la frontera. Cost: 140+80+97+101 = 418
<style ### Exemple de funcionament
Observacions
- En aquest exemple, els estats són les ciutats
- Problemes:
- Poden apareixer estats repetits en la frontera
- També es poden produir cicles
- L’ordre de les ciutats en la frontera determinarà:
- Si trobem o no la solució
- El cost de la solució
- El temps d’execució i l’espai de memòria necessari
Propietats dels algorismes de cerca
- Criteris per comparar algorismes de cerca
- Completitud: Garantia de trobar una solució si existeix
- Optimalitat: Garantia de trobar la solució òptima
- Complexitat temporal: Temps d’execució
- Complexitat espacial: Memòria necessària
Búsqueda no informada

Búsqueda no informada
Característiques
- No utilitza cap informació sobre el problema
- Aplica una estratègia de cerca fins que troba la solució
- Aquesta estratègia determina l’ordre en què s’exploraran els estats
- L’estrategia serà fixa, no pot canviar en funció del problema
- Alguns algorismes de cerca no informada:
- Amplitud, Profunditat, Cost uniforme, Profunditat limitada, Profunditat iterativa
Búsqueda en amplitud
- Estrategia utilitzable quan totes les accions tenen el mateix cost
- Explora tots els estats a una profunditat $p$ abans d’explorar els estats a profunditat $p+1$
- Garanteix trobar la solució òptima
- Definim la frontera com una cua (FIFO)
- Els estats ja visitats es guarden en una llista o conjunt (per evitar cicles)

Implementació
def cerca_amplada(estat_inicial):
"""Cerca en amplada en un problema."""
frontera = collections.deque([estat_inicial])
visitats = set()
while frontera:
estat = frontera.popleft()
visitats.add(estat)
if es_solucio(estat):
return estat
for succesor in succesors(estat):
if succesor not in visitats:
frontera.append(succesor)
Exemple: Botelles d’aigua (I)
- Estat inicial:
(0,0)- Estat final:(2,*)o(*, 2) - Funcio de succesió: Operacions de buidar, omplir i trasvasar
- Frontera = {<(0,0)>}
- Frontera = {<(0,0),(3,0)>, <(0,0),(0,4)>}
- Frontera = {<(0,0),(0,4)>, <(0,0),(3,0),(0,0)>, <(0,0) ,(3,0),(3,4)>, <(0,0),(3,0),(0,3)>}
- Frontera = {<(0,0),(3,0),(0,0)>, <(0,0),(3,0),(3,4)>, <(0,0),(3,0),(0,3)>, <(0,0),(0,4),(0,0)>, <(0,0),(0,4),(3,4)>, <(0,0),(0,4),(3,1)>}
- …
Exemple: Botelles d’aigua (II)
- Representació de l’arbre de cerca
- Cada node és un parell de valors (a,b) que representen l’estat de les botelles
- La busca en amplitud explora l’arbre per nivells
- Podem observar que solament s’explora un nombre molt reduït de tots els possibles estats

Propietats
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | Si l’espai de cerca és de memòria, la solució es trobarà en algun moment. |
| Optimalitat | Sí | Si totes les accions tenen el mateix cost, la primera solució trobada serà òptima.s |
| Complexitat temporal | $O(b^d)$ | On $b$ és el factor de ramificació i $d$ és la profunditat de la solució |
| Complexitat espacial | $O(b^d)$ | On $b$ és el factor de ramificació i $d$ és la profunditat de la solució |
Problemes
- La complexitat espacial és un problema real.
- Per exemple, suposem que cada estat ocupa 1KB i que el factor de ramificació és 10.
- Si la solució es troba a una profunditat de 10, necessitarem 10GB de memòria.
- Si es troba a una profunditat de 100, necessitarem 10TB.
- Si es troba a una profunditat de 1000, necessitarem 10PB.
- Típicament, ens quedarem sense espai abans de quedar-nos sense temps.
Búsqueda en profunditat
- L’estratègia de cerca en profunditat és similar a la de cerca en amplitud
- Utilitza una pila (LIFO) en lloc d’una cua
- Aquesta estratègia no garanteix trobar la solució òptima
- L’algorisme arriva fins a una profunditat màxima $m$ i després retrocedeix fins a trobar un camí alternatiu

Implementació
def cerca_profunditat(estat_inicial):
"""Cerca en profunditat en un problema."""
frontera = collections.deque([estat_inicial])
while frontera:
estat = frontera.pop()
if es_solucio(estat):
return estat
for succesor in succesors(estat):
if not cicle(problema, succesor):
frontera.append(succesor)
Exemple: Botelles d’aigua (I)
- Estat inicial:
(0,0)- Estat final:(2,*)o(*, 2) - Funcio de succesió: Operacions de buidar, omplir i trasvasar
- Frontera = {<(0,0)>}
- Frontera = {<(0,0), (3,0)>, <(0,0), (0,4)>}
- Frontera = {<(0,0),(3,0),(0,0)>, <(0,0),(3,0),(3,4)>, <(0,0),(3,0),(0,3)>, <(0,0),(0,4)>}
- Frontera = {<(0,0),(3,0),(0,0),(3,0)>, <(0,0),(3,0),(0,0),(0,4)> <(0,0), (3,0), (3,4)>, <(0,0),(3,0),(0,3)>, <(0,0),(0,4)>}
- …
Exemple: Botelles d’aigua (II)
- Representació de l’arbre de cerca
- Cada node és un parell de valors (a,b) que representen l’estat de les botelles
- La busca en profunditat explora l’arbre fins a trobar una solució
- Si no troba una solució, torna enrere fins a trobar un camí alternatiu
- Si les solucions son infinites, l’algorisme pot no acabar mai

Propietats
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | No | Si l’espai de cerca és finit, la solució es trobarà en algun moment |
| Optimalitat | No | La primera solució trobada no té perquè ser òptima |
| Complexitat temporal | $O(b^m)$ | On $b$ és el factor de ramificació i $m$ és la profunditat màxima de l’arbre. En valors d’$m$ molt grans, pot ser molt alta |
| Complexitat espacial | $O(bm)$ | On $b$ és el factor de ramificació i $m$ és la profunditat màxima de l’arbre. És molt millor que la de la cerca en amplitud si no hi ha cicles; si hi ha cicles, és la mateixa que la de la cerca en amplitud |
Quan utilitzar-la?
- En la pràctica, la cerca en profunditat és molt més ràpida que la cerca en amplitud
- La cerca en profunditat no necessita tant espai com la cerca en amplitud
- La cerca en profunditat és molt útil quan:
- El factor de ramificació és molt gran
- La solució es troba a una profunditat molt baixa
- No ens importa trobar la solució òptima
- Verifiquem que no es creen cicles
Búsqueda en profundidad limitada
- La cerca en profunditat limitada és una variant de la cerca en profunditat
- En aquest cas, la cerca s’atura quan s’arriba a una profunditat màxima $l$
- Si la solució es troba a una profunditat $d > l$, no es trobarà
- La cerca en profunditat limitada és completa si $l$ és suficientment gran
- Ens permet evitar el problema de la cerca en profunditat quan les solucions son infinites
Implementació
def cerca_profunditat_limitada(estat_inicial, l):
"""Cerca en profunditat limitada en un problema."""
frontera = collections.deque([estat_inicial])
while frontera:
estat = frontera.pop()
if es_solucio(estat):
return estat
for succesor in succesors(estat):
if not cicle(problema, succesor) and profunditat(succesor) < l:
frontera.append(succesor)
Búsqueda en profundidad iterativa
- Solució al problema de la cerca en amplitud y la cerca en profunditat utilitzant una única estratègia
- La cerca en profunditat iterativa és una cerca en profunditat limitada amb $l$ creixent
- Comença amb $l=0$ i va incrementant $l$ fins a trobar la solució

Traçat de l’algorisme (I)


Traçat de l’algorisme (II)

Traçat de l’algorisme (III)

Implementació
def cerca_profunditat_iterativa(estat_inicial):
"""Cerca en profunditat iterativa en un problema."""
l = 0
while True:
solucio = cerca_profunditat_limitada(estat_inicial, l)
if solucio is not None:
return solucio
l += 1
Propietats
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | Si l’espai de cerca és finit, la solució es trobarà en algun moment |
| Optimalitat | Sí | La primera solució trobada serà òptima |
| Complexitat temporal i espacial | Com la de la cerca en profunditat | (com a màxim) |
Búsqueda de cost uniforme
- La cerca de cost uniforme és una variant de la cerca en amplitud
- En aquest cas, la frontera s’ordena segons el cost del camí a cada estat (cua de prioritat)
- Estats visitats: de manera iterativa, es van visitant tots els que tenen un cost menor que l’actual
- Sí totes les accions tenen el mateix cost, la cerca de cost uniforme és equivalent a la cerca en amplitud

Exemple: Viatjar per Romania (I)
- Estat inicial: Arad
- Funcio de succesió: Carreteres.
- Cost: Distància entre ciutats (en Km)
- Comprovar si un estat és final: Estat = Bucharest
- Solució: Seqüència de ciutats que ens porten d’Arad a Bucharest

Exemple: Viatjar per Romania (II)
- Representació de l’arbre de cerca
- Cada node és un parell de valors (a,b) que representen l’estat de les botelles
- La busca en amplitud explora l’arbre per nivells
- Podem observar que solament s’explora un nombre molt reduït de tots els possibles estats

Implementació
def cerca_cost_uniforme(estat_inicial):
"""Cerca de cost uniforme en un problema."""
frontera = priority_queue([(0, estat_inicial)])
visitats = set()
while frontera:
cost_actual, estat = frontera.pop()
visitats.add(estat)
if es_solucio(estat):
return estat
for cost, succesor in succesors(estat):
if succesor not in visitats:
frontera.append(cost + cost_actual, succesor)
Propietats
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | Si l’espai de cerca és finit, la solució es trobarà en algun moment |
| Optimalitat | Sí | La primera solució trobada serà òptima |
| Complexitat temporal i espacial | $O(b^{1+C/\epsilon})$ | On $b$ és el factor de ramificació i $C$ és el cost de la solució òptima |
Gestió de fronteres
- La gestió de fronteres és un problema important en els algorismes de cerca
- Els algorismes que hem vist son tots molt semblants, la diferència està en com gestionen la frontera
- Conceptualment sempre es tracta d’una cua amb prioritat
- En la pràctica, per a les busquedes en profunditat i amplada podem utilitzar una cua o una pila
- Per estalviar-nos el sobrecost d’$O(log(n))$ de la cua de prioritat
- Podriem, fins i tot, programar una implementació on pugam variar l’objecte frontera.
Búsqueda informada

Definició
- L’algorisme de búsqueda de cost uniforme és un algoritme molt eficient, té, però alguns problemes
- Busca en totes les direccions, sense tenir en compte la direcció cap a la solució
- Per tant, analitza més estats dels que seria estrictament necessari
- En aquesta part de la unitat veurem técniques per solucionar aquestos problemes
Heurístiques
- Una heurística és:
- Una funció que ens permet estimar el cost d’arribar a la solució des d’un estat
- Dissenyada per un problema concret
- Heurístiques per rutes:
- Distància en línia recta (euclidiana)
- Distància manhattan

Exemple: Viatjar per Romania
- Heurística: Distància en línia recta (euclidiana)

Búsqueda voraç
- Si solament utilitzem la heurística per decidir quin estat de la frontera seguim:
- Búsqueda voraç
- Més eficient que la búsqueda de cost uniforme
- No garanteix trobar la solució òptima
height:330px

Búsqueda voraç
- En verd la ruta correcta i en roig la nostra
- Que podem fer perqué el nostre algorisme trobi la solució correcta?

Implementació
def cerca_voraç(estat_inicial):
"""Cerca voraç en un problema."""
frontera = priority_queue([(0, estat_inicial)])
visitats = set()
while frontera:
cost_actual, estat = frontera.pop()
visitats.add(estat)
if es_solucio(estat):
return estat
for cost, succesor in succesors(estat):
if succesor not in visitats:
frontera.append(heuristica(succesor), succesor)
Propietats
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | Si l’espai de cerca és finit, trobarà una solució en algun moment |
| Optimalitat | No | La primera solució trobada no té perquè ser òptima |
| Complexitat temporal i espacial | $O(bm)$ | On $b$ és el factor de ramificació i $m$ és la profunditat màxima de l’arbre |
A*
- L’algorisme A* és una combinació de la búsqueda de cost uniforme i la búsqueda voraç
- La búsqueda de cost uniforme ordena pel cost del camí o cost cap enrere: $g(n)$
- La búsqueda voraç ordena pel cost de la heurística o cost endavant: $h(n)$
- L’algorisme A* ordena per la suma dels dos: $f(n) = g(n) + h(n)$
Garanteix trobar la solució òptima (si $h(n)$ és admissible)
Exemple: Viatjar per Romania (I)
Exemple: Viatjar per Romania (II)
Exemple: Viatjar per Romania (III)
Implementació
def cerca_a_estrella(estat_inicial):
"""Cerca A* en un problema."""
frontera = priority_queue([(0, estat_inicial)])
visitats = set()
while frontera:
cost_actual, estat = frontera.pop()
visitats.add(estat)
if es_solucio(estat):
return estat
for cost, succesor in succesors(estat):
if succesor not in visitats:
cost_acumulat_h = cost + cost_actual + h(succesor)
frontera.append(cost_acumulat_h,
succesor)
Propietats
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | |
| Optimalitat | Sí | |
| Complexitat temporal i espacial | $O(b^d)$ | On $b$ és el factor de ramificació i $d$ és la profunditat de la solució |
Condició: Aquestes propietats es compleixen si la heurística és admissible
Heurístiques admissibles (I)
- Una heurística és admissible si:
- No sobreestima el cost de la solució
- És a dir, si el cost real de la solució és $C$, la heurística és admissible si $h(n) \leq C$
- Si la heurística NO és admissible:
- L’algorisme A* és equivalent a la búsqueda voraç
- Trobar una heurística admissible és un problema difícil.
Exemple: Puzzle 8 (I)
- Técnica útil redüir el problema a un problema més senzill
- Relaxació de les regles del joc
- Permetre que les peces s’intercanviïn entre elles
- Permetre que les peces es moguin a qualsevol posició, si està buida
- Permetre que les peces es moguin a qualsevol posició, sense restriccions (1+2)

Exemple: Puzzle 8 (II)
- La primera opció ens porta la heurística distància manhattan
- Equival a un problema on hem de lliscar les peces fins a la seva posició.
- Suma de les distàncies horitzontals i verticals de cada peça a la seva posició final
- És admissible perquè no sobreestima el cost de la solució
- La tercera opció ens porta la heurística nombre de peces fora de lloc
- Equival a un problema on hem de deixar directament en la seva posició.
- Suma de les peces que no estan a la seva posició final
- És admissible perquè no sobreestima el cost de la solució
Propietat Óptima de les heurístiques admissibles (I)
- Si $\textbf{n}$ és una ruta óptima fins a $n_d$ amb cost $g(n_d)$.
- $n’_g$ serà una ruta subòptima fins a $n_d$ amb cost $g(n’_d)$, sent $g(n’_d)$ > $g(n_d)$.
- $n’’$ serà una subpart de la ruta òptima desde la frontera
- Es possible que agafem $n’_g$ abans d’$n_d$?.
- No, perquè $f(n’_g)$ > $f(n_d)$ i $f(n’_g)$ > $f(n’’)$, perquè la heurística és admissible
- Així, $f(n’_g)$ > $f(n’’)$ > $f(n_d)$
- Les subrutes en la ruta òptima sempre seran més barates que en la ruta subòptima

Propietat Óptima de les heurístiques admissibles (II)
- A* explora els nodes en ordre creixent de $f(n)$
- Va agregant, de forma gradual, corves de nivell de grau $f$
- Cada corba de nivell representa un conjunt de nodes amb un valor d’$f(n)$ inferior a un valor concret

Propietat Óptima de les heurístiques admissibles (III)
- Si tenim dues heurístiques admissibles $h_1$ i $h_2$, amb $h_1(n) \leq h_2(n)$ per a tots els estats $n$
- Llavors, $h_2$ és més informativa que $h_1$
- Per tant, $h_2$ serà més eficient que $h_1$
- Es per això que, preferirem l’heurística Manhattan a l’heurística de peces fora de lloc

Limitacions de l’algorisme A*
- L’algorisme A* és òptim i una millora respecte a la búsqueda de cost uniforme
- Però, l’algorisme A* té dues limitacions:
- Espai de memòria: L’espai de memòria necessari pot ser molt gran
- Temps d’execució: El temps d’execució pot ser molt gran
- Per això, s’han desenvolupat variants de l’algorisme A* que intenten millorar aquestes limitacions
- En aquesta unitat veurem dues:
- A* de profunditat iterativa
- A* ponderat
A* de profunditat iterativa
- L’algorisme A* de profunditat iterativa és una variant de l’algorisme A*
- Molt semblant a l’algorisme de profunditat iterativa
- Utilitza la funció $f(n)$ per tallar, en compte de la profunditat
- Ens permet reduir l’espai de memòria necessari
- A costa de tindre que visitar alguns nodes més d’una vegada
Implementació (I)
def cerca_a_limitada(estat_inicial, l):
"""Cerca A* limitada en un problema."""
frontera = priority_queue([(0, estat_inicial)])
visitats = set()
while frontera:
cost_actual, estat = frontera.pop()
visitats.add(estat)
if es_solucio(estat):
return estat
for cost, succesor in succesors(estat):
if succesor not in visitats and cost_acumulat_h < l:
cost_acumulat_h = cost_actual + cost + h(succesor)
frontera.append(cost_acumulat_h, succesor)
Implementació (II)
def cerca_a_iterativa(estat_inicial):
"""Cerca A* iterativa en un problema."""
l = 0
while True:
solucio = cerca_a_limitada(estat_inicial, l)
if solucio is not None:
return solucio
l += 1
A* Ponderat
Definició
- L’algorisme A* ponderat és una variant de l’algorisme A*
- Es defineix un factor de ponderació $\epsilon$ que determina el pes de la heurística
- L’algorisme A* ponderat ordena per $f(n) = g(n) + \epsilon h(n)$
- Si $\epsilon = 1$, l’algorisme A* ponderat és equivalent a l’algorisme A*
- Si $\epsilon > 1$, l’algorisme A* ponderat és s’apropa a la búsqueda voraç
Utilitat
- L’algorisme A* ponderat és útil per:
- Reduir el cost de l’espai de memòria
- Reduir el cost de l’espai de temps
- A costa d’una solució no tan òptima
- En l’exemple de la dreta en una $W = 2$ (la b)
- S’estudien 7 vegades menys estats
- Per una solució un $5\%$ menys eficient

Implementació
def cerca_a_ponderat(estat_inicial, epsilon):
"""Cerca A* ponderat en un problema."""
frontera = priority_queue([(0, estat_inicial)])
visitats = set()
while frontera:
cost_actual, estat = frontera.pop()
visitats.add(estat)
if es_solucio(estat):
return estat
for cost, succesor in succesors(estat):
if succesor not in visitats:
cost_acumulat_h = cost_actual + cost + h(succesor) * epsilon
frontera.append(cost_acumulat_h, succesor)
Anytime A*
- Podem aprofitar l’algorisme A* ponderat per construir un algorisme Anytime A*
- Busquem el camí òptim amb un $\epsilon$ gran
- Anem reduint $\epsilon$ fins a que $\epsilon = 1$
- Així, obtenim una bona solució en un temps raonable
- Si tenim temps, podem seguir buscant una solució millor, fins arribar a la solució òptima

Implementació
def cerca_anytime_a(estat_inicial):
"""Cerca Anytime A* en un problema."""
epsilon = 100
while epsilon > 1:
solucio = cerca_a_ponderat(estat_inicial, epsilon)
yield solucio
epsilon /= 2
Demostració de búsquedes
Pac-Man
