
Els algorismes de cerca són algorismes de propòsit general
Sortida:
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

def cerca_amplada(estat_inicial):
"""Cerca en amplada en un problema."""
frontera = collections.deque([estat_inicial])
visitats = set()
while frontera:
estat = frontera.popleft()
if estat in visitats:
continue
visitats.add(estat)
if es_solucio(estat):
return estat
for succesor in succesors(estat):
if succesor not in visitats:
frontera.append(succesor)
(0,0) - Estat final: (2,*) o (*, 2)[(0,0)].(0,0): [(3,0), (0,4)].(3,0): [(0,4), (3,4), (0,3)].(0,4): [(3,4), (0,3), (3,4), (3,1)].(3,4) es descartarà si ja s’ha visitat.| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | Si el factor de ramificació és finit i hi ha memòria suficient, trobarà una solució finita. |
| Optimalitat | Sí | Si totes les accions tenen el mateix cost, la primera solució trobada serà òptima. |
| Complexitat temporal | On |
|
| Complexitat espacial | On |

def cerca_profunditat(estat_inicial):
frontera = [(estat_inicial, (estat_inicial,))]
while frontera:
estat, cami = frontera.pop()
if es_solucio(estat):
return estat
for succesor in succesors(estat):
if succesor not in cami:
frontera.append((succesor, cami + (succesor,)))
return None
(0,0) - Estat final: (2,*) o (*, 2)[(0,0)].(3,0) i (0,4), s’extrau (0,4) perquè la pila és LIFO.| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | No | Pot fallar si hi ha branques infinites; és completa en arbres finits. |
| Optimalitat | No | La primera solució trobada no té perquè ser òptima |
| Complexitat temporal | On |
|
| Complexitat espacial | On |
def cerca_profunditat_limitada(estat_inicial, limit):
frontera = [(estat_inicial, (estat_inicial,))]
tall = False
while frontera:
estat, cami = frontera.pop()
if es_solucio(estat):
return estat, tall
for succesor in succesors(estat):
if succesor not in cami:
if len(cami) - 1 < limit:
frontera.append((succesor, cami + (succesor,)))
else:
tall = True
return None, tall




def cerca_profunditat_iterativa(estat_inicial):
limit = 0
while True:
solucio, tall = cerca_profunditat_limitada(
estat_inicial, limit)
if solucio is not None or not tall:
return solucio
limit += 1
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | Si l'espai de cerca és finit, la solució es trobarà en algun moment |
| Optimalitat | Sí | Si totes les accions tenen el mateix cost. |
| Complexitat temporal | Per una solució a profunditat |
|
| Complexitat espacial | Cerca en arbre amb una pila de camins. |
En els exemples amb costos, succesors(estat) retorna parells (successor, cost).
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
import heapq
def cerca_cost_uniforme(estat_inicial):
"""Cerca de cost uniforme en un problema."""
frontera = [(0, estat_inicial)]
visitats = set()
while frontera:
cost_actual, estat = heapq.heappop(frontera)
# La frontera pot contenir el mateix estat més d'una vegada.
if estat in visitats:
continue
visitats.add(estat)
if es_solucio(estat):
return estat
for succesor, cost_accio in succesors(estat):
if succesor not in visitats:
heapq.heappush(frontera, (cost_actual + cost_accio, succesor))
| 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 | On |
import heapq
def cerca_voraç(estat_inicial):
"""Cerca voraç en un problema."""
frontera = [(0, estat_inicial)]
visitats = set()
while frontera:
cost_actual, estat = heapq.heappop(frontera)
visitats.add(estat)
if es_solucio(estat):
return estat
for succesor, cost in succesors(estat):
if succesor not in visitats:
heapq.heappush(frontera, (heuristica(succesor), succesor))
| 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 | En el pitjor cas, pot explorar i conservar una frontera exponencial. |
Amb heurística consistent i costos no negatius, aquesta implementació troba una solució òptima.
import heapq
def cerca_a_estrella(estat_inicial):
"""Cerca A* en un problema."""
frontera = [(h(estat_inicial), 0, estat_inicial)]
visitats = set()
while frontera:
_, cost_actual, estat = heapq.heappop(frontera)
if estat in visitats:
continue
visitats.add(estat)
if es_solucio(estat):
return estat, cost_actual
for succesor, cost_accio in succesors(estat):
if succesor not in visitats:
nou_cost = cost_actual + cost_accio
prioritat = nou_cost + h(succesor)
heapq.heappush(frontera, (prioritat, nou_cost, succesor))
| Propietat | Valor | Comentaris |
|---|---|---|
| Completitud | Sí | |
| Optimalitat | Sí | |
| Complexitat temporal i espacial | On |
Condició: Aquestes propietats es compleixen si la heurística és consistent (com la distància en línia recta de Romania).
def cerca_a_limitada(estat, g, limit, cami):
f = g + h(estat)
if f > limit:
return None, f
if es_solucio(estat):
return cami[:], f
proxim_limit = float("inf")
for succesor, cost in succesors(estat):
if succesor in cami:
continue
cami.append(succesor)
solucio, valor = cerca_a_limitada(
succesor, g + cost, limit, cami)
cami.pop()
if solucio is not None:
return solucio, valor
proxim_limit = min(proxim_limit, valor)
return None, proxim_limit
def cerca_a_iterativa(estat_inicial):
limit = h(estat_inicial)
while limit < float("inf"):
solucio, seguent = cerca_a_limitada(
estat_inicial, 0, limit, [estat_inicial])
if solucio is not None:
return solucio
limit = seguent
return None
import heapq
def cerca_a_ponderat(estat_inicial, epsilon):
frontera = [(epsilon * h(estat_inicial), 0, estat_inicial)]
costos = {estat_inicial: 0}
while frontera:
_, cost_actual, estat = heapq.heappop(frontera)
if cost_actual != costos[estat]:
continue
if es_solucio(estat):
return estat, cost_actual
for succesor, cost in succesors(estat):
nou_cost = cost_actual + cost
if nou_cost < costos.get(succesor, float("inf")):
costos[succesor] = nou_cost
prioritat = nou_cost + epsilon * h(succesor)
heapq.heappush(frontera, (prioritat, nou_cost, succesor))
return None
def cerca_anytime_a(estat_inicial):
millor_cost = float("inf")
for epsilon in (8, 4, 2, 1):
solucio = cerca_a_ponderat(estat_inicial, epsilon)
if solucio is not None and solucio[1] < millor_cost:
millor_cost = solucio[1]
yield solucio
