22
I.1.1 El algoritmo A* Introducción al algoritmo a* (star o asterisco) El algoritmo A* (conocido también como A estrella o asterisco) es un algoritmo de búsqueda que encuentra la ruta de menor coste entre dos puntos siempre y cuando se cumplan una serie de condiciones. Está clasificado dentro de los algoritmos de búsqueda en grafos ya que tiene la necesidad de dar a los mecanismos robóticos, vehiculares o virtuales un sistema de navegación autónomo. Es ampliamente utilizado en las ciencias de la computación para encontrar rutas y que tan transitable es una gráfica, es decir, se refiere al problema de visitar todos los nodos en una gráfica dada de forma particular , esto no es más que el proceso de trazado de la ruta más eficiente entre unos puntos llamados nodos. Este algoritmo goza de una aceptable y continua implementación gracias a su desempeño y precisión. Fue descrito por primera vez en 1968 como una extensión del algoritmo de Dijkstra (1959), por Peter Hart, Nils Nilsson y Bertran Raphael, que expusieron que el A* lograba un mejor desempeño con respecto al tiempo usando heurísticas.

El algoritmo a (asterisco)

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: El algoritmo a (asterisco)

I.1.1 El algoritmo A*

Introducción al algoritmo a* (star o asterisco)

El algoritmo A* (conocido también como A estrella o asterisco) es un algoritmo de

búsqueda que encuentra la ruta de menor coste entre dos puntos siempre y cuando se

cumplan una serie de condiciones. Está clasificado dentro de los algoritmos de búsqueda en

grafos ya que tiene la necesidad de dar a los mecanismos robóticos, vehiculares o virtuales

un sistema de navegación autónomo.

Es ampliamente utilizado en las ciencias de la computación para encontrar rutas y que tan

transitable es una gráfica, es decir, se refiere al problema de visitar todos los nodos en una

gráfica dada de forma particular , esto no es más que el proceso de trazado de la ruta más

eficiente entre unos puntos llamados nodos. Este algoritmo goza de una aceptable y

continua implementación gracias a su desempeño y precisión. Fue descrito por primera vez

en 1968 como una extensión del algoritmo de Dijkstra (1959), por Peter Hart, Nils Nilsson

y Bertran Raphael, que expusieron que el A* lograba un mejor desempeño con respecto al

tiempo usando heurísticas.

I.1.1 Orígenes del algoritmo A*

En 1964 Nils Nilsson inventó una heurística basada en aproximaciones para incrementar la

velocidad del algoritmo de Dijkstra. Este algoritmo fue llamado inicialmente como A1.

En 1967 Bertran Raphael hizo mejoras dramáticas sobre este algoritmo pero falló en

demostrar su optimalizad. Él llamó a este algoritmo como A2. Hart introdujo un argumento

que el A2 era óptimo usando una heurística consistente haciendo unos cambios menores. Su

comprobación del algoritmo también demostró que el A2 era el mejor algoritmo dadas

algunas condiciones. Así Hart llamó a este nuevo algoritmo con la sintaxis “Kleene star”

(debido a que representa una operación con solamente un operando [5, 6]) por ser un

algoritmo que empieza con la letra A e incluye todas las versiones de números posibles o

A*. El algoritmo A*, (leído A estrella) es un algoritmo de búsqueda en grafos. Fue

presentado por Peter E. Hart y Nils J. Nilsson (1968), y Bertram Raphael (1968), el

Page 2: El algoritmo a (asterisco)

algoritmo encuentra, siempre y cuando se cumplan unas determinadas condiciones, el

camino de menor coste entre una condición inicial y una condición meta.

El algoritmo A* es usualmente utilizado en los problemas para encontrar la mejor ruta o

camino, lo que realiza el algoritmo es construir todas las rutas desde un punto inicial hasta

encontrar alguna que llegue al nodo final o meta. De éste modo solamente construye

aquellas rutas que son candidatas a formar una solución o camino desde el inicio hasta el

nodo final. Para poder determinar que rutas son las que tienen mayor probabilidad de llegar

al nodo meta, el algoritmo utiliza una heurística basada en la distancia de cualquier punto

dado hacía la meta.

Donde se diferencia el algoritmo A* de otros algoritmos avaros de “best-first search” es el

hecho de que va tomando en cuenta la distancia que ya ha recorrido hasta el momento,

haciendo de este modo una respuesta mucho más completa y óptima.

Este algoritmo en particular es uno de los más adecuados para este proyecto de

investigación ya que según los creadores del mismo es un algoritmo que encuentra el

camino de menor coste de un recorrido A aun recorrido B. Aplicando dicho algoritmo a

este proyecto de investigación pretendemos obtener un buen resultado en cuanto a la

optimización de rutas de transportes.

I.1.1 Descripción del algoritmo A*

Es un algoritmo que se encarga de encontrar la ruta que representa un menor costo entre un

punto A y otro B. Es una técnica de búsqueda para grafos que utiliza una función heurística

(ya que trata de métodos exploratorios durante la resolución del problema en el cual la

solución se descubre por la evaluación del progreso logrado en la búsqueda de un resultado

final denotada f ’(x), la cual es una aproximación a f(x) que proporciona la verdadera

evaluación de un nodo para determinar el orden en que se realiza la visita a los otros nodos

del árbol. La función de evaluación es el resultado de la suma de otras dos funciones, una

que indica el coste del camino que se ha seguido hasta un cierto nodo la cual se representa

como g(x) y otra que nos da una estimación de la distancia del punto o nodo en que nos

encontramos hasta la meta que está representada como h(x). Entonces la función de

evaluación es el resultado de la suma de h(x) y g(x).

Page 3: El algoritmo a (asterisco)

Entonces cada una de ellas se representa de la siguiente manera:

Donde:

costo: representa el valor explícito de movernos de nuestro punto actual al siguiente en

alguna dirección dada, si no se especifica se toma como unitario ya que pertenece a una

distribución uniforme.

abs: representa el valor absoluto de la operación dentro del paréntesis.

nodox, nodoy: son las coordenadas (x, y) del nodo en el que nos encontramos actualmente.

objetivox , objetivoy : representa las coordenadas de posición de nuestra meta u objetivo al

cual deseamos llegar.

Cuando comenzamos a analizar el problema nuestro nodo origen tiene un valor inicial 0

(cero) tanto en h como en g.

Posteriormente g(x) se representa de la siguiente manera:

Donde:

α: representa un valor entre 0 y 1 dado por las circunstancias del problema a resolver.

padreg : es el valor obtenido de la ecuación g(x) del anterior nodo padre. Cuando iniciamos

los cálculos por primera vez, este valor es 0 para el nodo origen.

En esta ecuación debemos prestar atención especial conforme vayamos avanzado en el

“pathfinding” ya que debemos sumar al resultado obtenido en la ecuación anterior el

mismo valor g del padre anterior de nueva forma, es decir, tendríamos algo así:

De esta forma podemos empezar a realizar los cálculos para cada uno de los nodos que se

vayan analizando. Este algoritmo consiste entonces en atravesar una gráfica (de forma

definida normalmente) siguiendo una ruta con el menor costo conocido manteniendo una

cola sorteada de prioridades con segmentos de rutas alternas a lo largo del camino para que

si en un momento dado la ruta que se está siguiendo arroja un valor (costo) superior en

Page 4: El algoritmo a (asterisco)

comparación con otro segmento de ruta encontrado, esta abandona esa ruta actual de alto

coste y en vez de ella toma la que le brinda un camino más “barato”. De esta forma el

proceso sigue hasta alcanzar la meta u objetivo.

Empezando en un nodo inicial dado, el algoritmo expande el nodo con el menor valor de

f’(x). Este algoritmo mantiene un conjunto de soluciones parciales almacenadas en una cola

de prioridad. El proceso continua hasta que una meta tiene un valor f’(x) menor que

cualquier otro nodo en la cola o hasta que el árbol ha sido recorrido completamente. Como

aspecto positivo podemos considerar que ningún otro algoritmo óptimo nos garantiza

expandir menos nodos que A*, pero éste requiere un alto consumo de memoria

El siguiente pseudocódigo describe el algoritmo:

Initialize OPEN list

Initialize CLOSED list

Create goal node; call it node_goal

Create start node; call it node_start

Add node_start to the OPEN list

While the OPEN list is not empty

{

Get node n off de OPEN list with the lowest f(n)

Add n to the CLOSED list

If n is the same as node_goal we have found the solution; return Solution(n)

Generate each successor node n’ of n

For each successor node n’ of n

{

Set the parent of n’ to n

Set h(n’) to be the heuristically estimate distance to node_goal

Set g(n’) to be g(n) plus the cost to get to n’ from n

Set f(n’) to be g(n’) plus h(n’)

If n’ is on the OPEN list and the existing one is as good or better, then

discard n’ and continue

If n’ is on the CLOSED list and the existing one is as good or better, then

Page 5: El algoritmo a (asterisco)

discard n’ and continue

Remove occurrences of n’ from OPEN and CLOSED

Add n’ to the OPEN list

}

}

Return failure (if we reach this point we’ve searched all reachable nodes and still haven’t

found the solution, therefore one doesn’t exist).

Podemos describir el algoritmo de la siguiente manera:

1) Colocar el nodo inicial en la lista de ABIERTOS.

2) Verificar si la lista de ABIERTOS está vacía.

a. Si está vacía entonces no se ha encontrado una solución. Fin.

b. Si no está vacía entonces hay que realizar los cálculos de h, g y f correspondientes para

obtener el nodo con el mejor valor en f (el de menor costo) de la lista de ABIERTOS y se

adiciona a CERRADOS.

3) Evaluar si el nodo que se acaba de enviar a CERRADOS es el objetivo.

a. Si es el nodo objetivo entonces se encontró la solución.

b. De lo contrario se prosigue con las siguientes operaciones.

4) El nodo sucesor ahora se toma como el nodo actual.

5) Calcular los valores de g, h y f del nodo.

6) El nodo actual posee mejor valor en f que su nodo padre?

a. Si posee mejor valor entonces, remueve las ocurrencias de la lista de cerrados. Adiciona

sus sucesores (nodos hijos) a la lista de abiertos y regresa al punto 2.

b. Si no, termina la operación y regresa a evaluar la condición de si la lista de

ABIERTOS se encuentra vacía.

Page 6: El algoritmo a (asterisco)

I.1.1 Aplicaciones del algoritmo A*

De manera general este algoritmo se utiliza para encontrar el camino más corto entre dos

puntos dados, pero dentro de sus otras aplicaciones se utiliza en juegos para determinar el

recorrido que un objeto debe realizar; un ejemplo de ello es el videojuego pacman en el que

se aplicaba al comportamiento de los fantasmitas y en la resolución de los problemas de

Sudoku de 8 variables. También se puede utilizar para resolver el cubo Rubik

mostrándonos cómo hacerlo con la menor cantidad de movidas.

Debemos tener en cuenta que hay circunstancias en las que no es sencillo encontrar una

buena función heurística pero también es válido especificar que sea cero ya que la misma

debe ser estimada por defecto.

A continuación se muestra una aplicación desarrollada en modo consola la cual consiste en

seleccionar de una cuadrícula de 4x5 un punto inicial y un punto final; con esos puntos el

algoritmo deberá indicar el recorrido que se tendrá que hacer para llegar de uno a otro de la

forma más económica posible. El recorrido estará truncado por una serie de “paredes” que

dificultarán el libre trazo de la ruta.

Page 7: El algoritmo a (asterisco)

Ilustración 1. Pantalla inicial para selección de puntos de origen y destino.En la figura 1 se puede apreciar a través del uso de ‘ * ’ las barreras que por naturaleza se

nos están infligiendo, mismas que provocarán que el algoritmo tome una serie de

decisiones para elegir el camino que más le conviene.

Ilustración 2. Pantalla que muestra el resultado de la búsqueda.

En la figura anterior ya se muestra el resultado obtenido de haberle indicado al algoritmo

que se deseaba ir del punto 1 al 18.

En la última parte que se muestra en la ventana donde nos especifica el trayecto o la ruta a

recorrer se lee de derecha izquierda siguiendo el orden de las flechas.

Page 8: El algoritmo a (asterisco)

I.1.2 Motivación y descripción del algoritmo A*

El problema de algunos algoritmos de búsqueda en grafos informados, como puede ser el

algoritmo voraz, es que se guían en exclusiva por la función heurística, la cual puede no

indicar el camino de coste más bajo, o por el coste real de desplazarse de un nodo a otro

(como los algoritmos de escalada), pudiéndose dar el caso de que sea necesario realizar un

movimiento de coste mayor para alcanzar la solución. Es por ello bastante intuitivo el

hecho de que un buen algoritmo de búsqueda informada debería tener en cuenta ambos

factores, el valor heurístico de los nodos y el coste real del recorrido.

Así, el algoritmo A* utiliza una función de evaluación , donde

representa el valor heurístico del nodo a evaluar desde el actual, n, hasta el final, y

, el coste real del camino recorrido para llegar a dicho nodo, n, desde el nodo inicial.

A* mantiene dos estructuras de datos auxiliares, que podemos denominar abiertos,

implementado como una cola de prioridad (ordenada por el valor de cada nodo), y

cerrados, donde se guarda la información de los nodos que ya han sido visitados. En cada

paso del algoritmo, se expande el nodo que esté primero en abiertos, y en caso de que no

sea un nodo objetivo, calcula la de todos sus hijos, los inserta en abiertos, y pasa el

nodo evaluado a cerrados.

El algoritmo es una combinación entre búsquedas del tipo primero en anchura con primero

en profundidad: mientras que tiende a primero en profundidad, tiende a primero

en anchura. De este modo, se cambia de camino de búsqueda cada vez que existen nodos

más prometedores.

I.1.3 Propiedades del algoritmo

Como todo algoritmo de búsqueda en amplitud, A* es un algoritmo completo: en caso de

existir una solución, siempre dará con ella.

Si para todo nodo n del grafo se cumple , nos encontramos ante una búsqueda

voraz. Si para todo nodo n del grafo se cumple , A* pasa a ser una búsqueda de

coste uniforme no informada.

Page 9: El algoritmo a (asterisco)

Para garantizar la optimalidad del algoritmo, la función debe ser admisible, esto es,

que no sobrestime el coste real de alcanzar el nodo objetivo.

De no cumplirse dicha condición, el algoritmo pasa a denominarse simplemente A, y a

pesar de seguir siendo completo, no se asegura que el resultado obtenido sea el camino de

coste mínimo. Asimismo, si garantizamos que es consistente (o monótona), es decir,

que para cualquier nodo y cualquiera de sus sucesores, el coste estimado de alcanzar el

objetivo desde n no es mayor que el de alcanzar el sucesor más el coste de alcanzar el

objetivo desde el sucesor.

I.1.4 Complejidad computacional del algoritmo

La complejidad computacional del algoritmo está íntimamente relacionada con la calidad

de la heurística que se utilice en el problema. En el caso peor, con una heurística de pésima

calidad, la complejidad será exponencial, mientras que en el caso mejor, con una buena

, el algoritmo se ejecutará en tiempo lineal. Para que esto último suceda, se debe

cumplir que

donde h* es una heurística óptima para el problema,

como por ejemplo, el coste real de alcanzar el objetivo.

I.1.5 Complejidad en memoria

El espacio requerido por A* para ser ejecutado es su mayor problema. Dado que tiene que

almacenar todos los posibles siguientes nodos de cada estado, la cantidad de memoria que

requerirá será exponencial con respecto al tamaño del problema. Para solucionar este

problema, se han propuesto diversas variaciones de este algoritmo, como pueden ser RTA*,

IDA* o SMA*.

Page 10: El algoritmo a (asterisco)

I.1.6 Implementación en pseudocódigo

I.1.1 Tratar punto

.:= . // coste del camino hasta .

caso . = . perteneciente a () si g(.) < g(.) entonces // (-----) // nos quedamos con el camino de menor coste .:= MEJORNODO actualizar g(.) y f'(.) propagar g a . de . eliminar . añadir . a ._MEJORNODOcaso . = . perteneciente a )-----( si g(.) < g(.) entonces // nos quedamos con el camino de menor coste .:= MEJORNODO actualizar g(.) y f'(.) eliminar . añadir . a ._MEJORNODOcaso . no estaba en ).( ni (.) añadir . a ).( añadir . a ._MEJORNODO f'(.) := g(.) + h'(.)

I.1.2 Implementación en pseudocódigo

ABIERTOS := [INICIAL] //inicialización CERRADOS := [] f'(INICIAL) := h'(INICIAL) repetir si ABIERTOS = [] entonces FALLO si no // quedan nodos extraer MEJORNODO de ABIERTOS con f' mínima // cola de prioridad mover MEJORNODO de ABIERTOS a CERRADOS si MEJORNODO contiene estado_objetivo entonces SOLUCION_ENCONTRADA := TRUE si no generar SUCESORES de MEJORNODO para cada SUCESOR hacer TRATAR_SUCESOR hasta SOLUCION_ENCONTRADA o FALLO

I.1.3 TRATAR_SUCESOR

SUCESOR.ANTERIOR := VIEJO // coste del camino hasta SUCESOR

caso SUCESOR = VIEJO perteneciente a CERRADOS

Page 11: El algoritmo a (asterisco)

si g(SUCESOR) < g(VIEJO) entonces // (no si monotonía) // nos quedamos con el camino de menor coste VIEJO.ANTERIOR := MEJORNODO actualizar g(VIEJO) y f'(VIEJO) propagar g a sucesores de VIEJO eliminar SUCESOR añadir VIEJO a SUCESORES_MEJORNODO caso SUCESOR = VIEJO perteneciente a ABIERTOS si g(SUCESOR) < g(VIEJO) entonces // nos quedamos con el camino de menor coste VIEJO.ANTERIOR := MEJORNODO actualizar g(VIEJO) y f'(VIEJO) eliminar SUCESOR añadir VIEJO a SUCESORES_MEJORNODO caso SUCESOR no estaba en ABIERTOS ni CERRADOS añadir SUCESOR a ABIERTOS añadir SUCESOR a SUCESORES_MEJORNODO f'(SUCESOR) := g(SUCESOR) + h'(SUCESOR)

I.1.4 Lectura del Procedimiento del algoritmo A*

Según Nils J. Nilsson (1968).

1. Empezar con ABIERTO conteniendo sólo el nodo inicial. Poner el valor g de ese nodo a

O, su valor h' al que corresponda, y su valor f' a h' + O, es decir h'. Inicializar CERRADOS

como la lista vacía.

2. Repetir el siguiente procedimiento hasta que se encuentre el nodo meta: si no existen

nodos en ABIERTOS, informar del fallo. De lo contrario, tomar aquel nodo de ABIERTOS

con mejor valor f'. Llamarle MEJORNODO. Quitarlo de ABIERTOS. Colocarlo en

CERRADOS. Mirar si MEJORNODO es un nodo meta. Si lo es, salir e informar de la

solución (bien sea MEJORNODO si lo único que queremos es el nodo, o el camino que se

ha creado entre el estado inicial y MEJORNODO si estamos interesados en el camino). En

caso contrario, generar los sucesores de MEJORNODO, pero no poner MEJORNODO

apuntando aún a ellos (antes debemos mirar si alguno de ellos ya ha sido generado). Para

cada SUCESOR, hacer lo siguiente:

1. Poner a SUCESOR apuntando a MEJORNODO. Estos enlaces hacia atrás hacen posible

recuperar el camino una vez que se ha encontrado la solución.

Page 12: El algoritmo a (asterisco)

2. Calcular g (SUCESOR) = g (MEJORNODO) + costes de ir desde MEJORNODO hasta

SUCESOR.

3. Mirar si SUCESOR está contenido en ABIERTOS (es decir, si ya ha sido generado pero

no procesado). Si es así, llamemos a ese nodo VIEJO. Puesto que este nodo ya existe en el

grafo, podemos desechar SUCESOR, y añadir VIEJO a la lista de los sucesores de

MEJORNODO. Ahora debemos decidir si el enlace paterno de VIEJO debería apuntar a

MEJORNODO. Debería ocurrir así si el camino que hemos encontrado hasta SUCESOR es

de menor coste que el mejor camino actual hasta VIEJO (puesto que SUCESOR y VIEJO

son en realidad el mismo nodo). Para ver si cuesta menos llegar hasta VIEJO a través de su

padre actual o hasta SUCESOR a través de MEJORNODO, comparar sus valores g. Si

VIEJO tiene menor (o igual) coste, no necesitamos hacer nada.

Si SUCESOR tiene menor coste, entonces hacer que el enlace paterno de VIEJO apunte

hacia MEJORNODO, grabar el nuevo camino óptimo en g (VIEJO), y actualizar f'(VIEJO).

4. Si SUCESOR no estaba en ABIERTOS, ver si estaba en CERRADOS. En caso

afirmativo, llamar VIEJO al nodo de CERRADOS, y añadir VIEJO a la lista de los

sucesores de MEJORNODO. Mirar si el nuevo camino es mejor que el viejo tal como se

hizo en el paso 2.3 y actualizar apropiadamente el enlace paterno y los valores de g y f'. Si

acabamos de encontrar un mejor camino a VIEJO, debemos propagar la mejora a los

sucesores de VIEJO. Esto es un poco delicado. VIEJO apunta a sus sucesores. Cada sucesor

a su vez apunta a sus sucesores, y así sucesivamente hasta que cada rama termina en un

nodo que bien ya está en ABIERTOS o no tiene sucesores. Por tanto, para propagar el

nuevo coste hacia abajo, podemos hacer una búsqueda transversal en profundidad del árbol,

empezando en VIEJO, cambiando el valor g de cada nodo (y por tanto su valor f'),

terminando cada rama cuando se alcanza bien un nodo sin sucesores o bien un nodo para el

que ya se ha encontrado un camino equivalente o mejor. Es fácil examinar esta condición.

El enlace paterno de cada nodo apunta hacia atrás a su mejor predecesor conocido.

Conforme propagamos a un nodo siguiente, debemos mirar si su predecesor apunta al nodo

del que estamos viniendo. Si lo hace así, debemos continuar la propagación. Si no, su valor

g ya refleja el mejor camino del que forma parte. Por tanto la propagación debe parar allí.

Page 13: El algoritmo a (asterisco)

Pero es posible que al propagar el nuevo valor de g hacia abajo, el camino que estamos

siguiendo pueda volverse mejor que el camino a través del antecesor actual. Por tanto

debemos comparar los dos. Si el camino a través del antecesor actual es aún mejor,

debemos detener la propagación. Si el camino a través del cual estamos propagando es

ahora mejor, inicializar el antecesor y continuar la propagación.

5. Si SUCESOR no estaba ya en ABIERTOS o en CERRADOS, ponerlo en ABIERTOS y

añadirlo a la lista de sucesores de MEJORNODO. Calcular f'(SUCESOR) = g(SUCESOR)

+ h'(SUCESOR).

Podemos hacer algunas observaciones interesantes sobre este algoritmo. La primera

concierne al papel de la función g. Nos permite escoger el nodo a expandir a continuación

sobre la base, no sólo de cuán bueno parece el nodo en sí mismo (medido por h'), sino

también sobre la base de cuán bueno era el camino hasta el nodo. Al incorporar g en f' no

siempre elegiremos como nuestro siguiente nodo a expandir el nodo que parece más

cercano a la meta. Esto es Útil si nos preocupa el camino que elijamos. Pero si sólo nos

importa llegar a una solución de la forma que sea, podemos definir siempre g como 0, con

lo que también elegiríamos siempre el nodo que parece más cercano a la meta. Si queremos

encontrar un camino que tenga el menor número de pasos, entonces debemos poner el coste

de ir desde un nodo a su sucesor como una constante, usualmente 1. Si, por otra parte,

queremos encontrar el camino de menor coste y algunos operadores cuestan más que otros,

entonces debemos poner el coste de ir de un nodo a otro de forma que refleje dichos costes.

Así pues, el algoritmo A* puede usarse tanto si estamos interesados en encontrar un camino

con el coste total mínimo, como si simplemente queremos encontrar cualquier camino de la

forma más rápida posible.

La segunda observación atañe a h', el estimador de h, la distancia de un nodo a la meta. Si

h' es un estimador perfecto de h entonces A* convergerá. Inmediatamente a la meta sin

búsqueda. Cuanto mejor sea h' más cerca estaremos de este enfoque directo. Si por otra

parte, h' es siempre O, la búsqueda estará controlada por g. Si g también es O, la estrategia

de búsqueda se realizará al azar. Si g es siempre 1, se realizará una búsqueda en anchura.

Todos los nodos de un nivel tendrán valores g más bajos, y por tanto f' más bajos, que

Page 14: El algoritmo a (asterisco)

cualquier nodo del siguiente nivel. ¿Qué ocurre, por otra parte, si h' no es ni perfecto ni O?

¿Podemos decir algo interesante sobre el comportamiento de la búsqueda? La respuesta es

afirmativa si podemos garantizar que h' nunca sobrestimará h. En ese caso, el algoritmo A*

garantiza que encontraremos un camino óptimo (determinado por g) a la meta, si éste

existe. Podemos ver esto fácilmente a partir de algunos ejemplos.

Consideremos la situación mostrada en la figura 3.13. Supongamos que el coste de todos

los arcos es 1. Inicialmente, todos los nodos excepto A están en ABIERTOS (aunque la

figura muestra la situación dos pasos más tarde, después de haber expandido B y E).

Para cada nodo, se indica f' como la suma de h' y g. En este ejemplo, el nodo B tiene la f'

más baja, 4, por lo que lo expandiremos en primer lugar. Supongamos que tiene un único

sucesor E, que también parece estar a tres movimientos de la meta. Ahora f'(E) es 5, igual

que f'(C). Supongamos que resolvemos esta disyuntiva a favor del camino que estábamos

siguiendo actualmente. Entonces expandiremos E a continuación. Supongamos que también

él tiene un único sucesor F', también a tres movimientos de la meta. Es evidente que

estamos haciendo movimientos sin realizar ningún progreso. Pero f'(F) = 6, que es mayor

que f'(C). Por tanto expandiremos C a continuación. Así vemos que al subestimar h(B)

hemos desperdiciado algún esfuerzo. Pero en un momento u otro descubrimos que B estaba

más lejos de lo que pensábamos, por lo que podemos regresar y encontrar otro camino.