SlideShare a Scribd company logo
1 of 14
Download to read offline
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
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).
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
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
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.
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.
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.

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
nodo evaluado a cerrados.

de todos sus hijos, los inserta en abiertos, y pasa el
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.
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
que para cualquier nodo

es consistente (o monótona), es decir,

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*.

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 ._MEJORNODO
caso . = . perteneciente a )-----(
si g(.) < g(.) entonces
// nos quedamos con el camino de menor coste
.:= MEJORNODO
actualizar g(.) y f'(.)
eliminar .
añadir . a ._MEJORNODO
caso . 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
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.
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í.
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
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.

More Related Content

What's hot

hashing y colisiones
hashing y colisioneshashing y colisiones
hashing y colisionesemiru48
 
Ejercicios de búsqueda a Ciegas y Búsqueda informada
Ejercicios de búsqueda a Ciegas y Búsqueda informadaEjercicios de búsqueda a Ciegas y Búsqueda informada
Ejercicios de búsqueda a Ciegas y Búsqueda informadaHéctor Estigarribia
 
Programación 3: Grafos, representación y operaciones
Programación 3: Grafos, representación y operacionesProgramación 3: Grafos, representación y operaciones
Programación 3: Grafos, representación y operacionesAngel Vázquez Patiño
 
Diferencia entre algoritmo de path finding y algoritmo de dijkstra
Diferencia entre algoritmo de path finding y algoritmo de dijkstraDiferencia entre algoritmo de path finding y algoritmo de dijkstra
Diferencia entre algoritmo de path finding y algoritmo de dijkstranacasma
 
Ordenamiento Por MéTodo De InsercióN Binaria
Ordenamiento  Por MéTodo De InsercióN BinariaOrdenamiento  Por MéTodo De InsercióN Binaria
Ordenamiento Por MéTodo De InsercióN BinariaAngie Suarez
 
Clases y objetos de java
Clases y objetos de javaClases y objetos de java
Clases y objetos de javainnovalabcun
 
Diagramas de contexto para blog
Diagramas de contexto para blogDiagramas de contexto para blog
Diagramas de contexto para blogmartinvazquez
 
Ascenso a la Colina
Ascenso a la ColinaAscenso a la Colina
Ascenso a la ColinaTutor4uDev
 
Desarrollo de aplicaciones web con casos de uso
Desarrollo de aplicaciones web  con casos de usoDesarrollo de aplicaciones web  con casos de uso
Desarrollo de aplicaciones web con casos de usoJosafat Mtz
 
Creación de archivos de clases en c#
Creación de archivos de clases en c#Creación de archivos de clases en c#
Creación de archivos de clases en c#UVM
 

What's hot (20)

Estructuras en c++
Estructuras en c++Estructuras en c++
Estructuras en c++
 
PROGRAMACIÓN ORIENTADA A OBJETOS
PROGRAMACIÓN ORIENTADA A OBJETOSPROGRAMACIÓN ORIENTADA A OBJETOS
PROGRAMACIÓN ORIENTADA A OBJETOS
 
hashing y colisiones
hashing y colisioneshashing y colisiones
hashing y colisiones
 
8 reinas
8 reinas8 reinas
8 reinas
 
Ejercicios de búsqueda a Ciegas y Búsqueda informada
Ejercicios de búsqueda a Ciegas y Búsqueda informadaEjercicios de búsqueda a Ciegas y Búsqueda informada
Ejercicios de búsqueda a Ciegas y Búsqueda informada
 
Ejemplo de aplicación cliente-servidor en C#
Ejemplo de aplicación cliente-servidor  en C#Ejemplo de aplicación cliente-servidor  en C#
Ejemplo de aplicación cliente-servidor en C#
 
Metodo de busqueda
Metodo de busquedaMetodo de busqueda
Metodo de busqueda
 
Problema de las 8 reinas
Problema de las 8 reinasProblema de las 8 reinas
Problema de las 8 reinas
 
Programación 3: Grafos, representación y operaciones
Programación 3: Grafos, representación y operacionesProgramación 3: Grafos, representación y operaciones
Programación 3: Grafos, representación y operaciones
 
Diagramas UML
Diagramas UMLDiagramas UML
Diagramas UML
 
Diferencia entre algoritmo de path finding y algoritmo de dijkstra
Diferencia entre algoritmo de path finding y algoritmo de dijkstraDiferencia entre algoritmo de path finding y algoritmo de dijkstra
Diferencia entre algoritmo de path finding y algoritmo de dijkstra
 
Ordenamiento Por MéTodo De InsercióN Binaria
Ordenamiento  Por MéTodo De InsercióN BinariaOrdenamiento  Por MéTodo De InsercióN Binaria
Ordenamiento Por MéTodo De InsercióN Binaria
 
Clases y objetos de java
Clases y objetos de javaClases y objetos de java
Clases y objetos de java
 
Tipos de Datos Abstractos.
Tipos de Datos Abstractos.Tipos de Datos Abstractos.
Tipos de Datos Abstractos.
 
Diagramas de contexto para blog
Diagramas de contexto para blogDiagramas de contexto para blog
Diagramas de contexto para blog
 
Ascenso a la Colina
Ascenso a la ColinaAscenso a la Colina
Ascenso a la Colina
 
Codificación de Huffman
Codificación de HuffmanCodificación de Huffman
Codificación de Huffman
 
Listas
ListasListas
Listas
 
Desarrollo de aplicaciones web con casos de uso
Desarrollo de aplicaciones web  con casos de usoDesarrollo de aplicaciones web  con casos de uso
Desarrollo de aplicaciones web con casos de uso
 
Creación de archivos de clases en c#
Creación de archivos de clases en c#Creación de archivos de clases en c#
Creación de archivos de clases en c#
 

Viewers also liked

Tipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia ArtificialTipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia ArtificialAlan López
 
Búsqueda Sistemática: Marco Teórico
Búsqueda Sistemática: Marco TeóricoBúsqueda Sistemática: Marco Teórico
Búsqueda Sistemática: Marco TeóricoCONASIN PERU
 
Tipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia ArtificialTipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia ArtificialJuank Grifin
 
diapositivas algoritmos
diapositivas algoritmos diapositivas algoritmos
diapositivas algoritmos TiffanyMartinez
 
Busqueda Ascenso Colinas
Busqueda Ascenso ColinasBusqueda Ascenso Colinas
Busqueda Ascenso ColinasJeffoG92
 
Problema de la ocho reinas. Implementación en Prolog.
Problema de la ocho reinas. Implementación en Prolog.Problema de la ocho reinas. Implementación en Prolog.
Problema de la ocho reinas. Implementación en Prolog.Mayra Villanueva
 
Algoritmo de Dijkstra
Algoritmo de DijkstraAlgoritmo de Dijkstra
Algoritmo de DijkstraPedro Miranda
 
Tipos de búsqueda en inteligencia artificial
Tipos de búsqueda  en inteligencia artificialTipos de búsqueda  en inteligencia artificial
Tipos de búsqueda en inteligencia artificialHenry Cambal
 
Algoritmos para matlab
Algoritmos para matlabAlgoritmos para matlab
Algoritmos para matlabVitoto96
 
Características de un algoritmo
Características de un algoritmoCaracterísticas de un algoritmo
Características de un algoritmoroxanaparra28
 
Ejemplos de Algoritmos
Ejemplos de AlgoritmosEjemplos de Algoritmos
Ejemplos de AlgoritmosPepe Xdsasda
 

Viewers also liked (16)

Búsqueda A*
Búsqueda A*Búsqueda A*
Búsqueda A*
 
Tipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia ArtificialTipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia Artificial
 
Búsqueda Sistemática: Marco Teórico
Búsqueda Sistemática: Marco TeóricoBúsqueda Sistemática: Marco Teórico
Búsqueda Sistemática: Marco Teórico
 
Tipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia ArtificialTipos de búsqueda en Inteligencia Artificial
Tipos de búsqueda en Inteligencia Artificial
 
diapositivas algoritmos
diapositivas algoritmos diapositivas algoritmos
diapositivas algoritmos
 
Busqueda informada y explorada
Busqueda informada y exploradaBusqueda informada y explorada
Busqueda informada y explorada
 
Busqueda Ascenso Colinas
Busqueda Ascenso ColinasBusqueda Ascenso Colinas
Busqueda Ascenso Colinas
 
Problema 8 puzzle
Problema 8 puzzleProblema 8 puzzle
Problema 8 puzzle
 
PODA ALFA-BETA
PODA ALFA-BETAPODA ALFA-BETA
PODA ALFA-BETA
 
Problema de la ocho reinas. Implementación en Prolog.
Problema de la ocho reinas. Implementación en Prolog.Problema de la ocho reinas. Implementación en Prolog.
Problema de la ocho reinas. Implementación en Prolog.
 
Algoritmo de Dijkstra
Algoritmo de DijkstraAlgoritmo de Dijkstra
Algoritmo de Dijkstra
 
Tipos de búsqueda en inteligencia artificial
Tipos de búsqueda  en inteligencia artificialTipos de búsqueda  en inteligencia artificial
Tipos de búsqueda en inteligencia artificial
 
Algoritmo en powerpoint
Algoritmo en powerpointAlgoritmo en powerpoint
Algoritmo en powerpoint
 
Algoritmos para matlab
Algoritmos para matlabAlgoritmos para matlab
Algoritmos para matlab
 
Características de un algoritmo
Características de un algoritmoCaracterísticas de un algoritmo
Características de un algoritmo
 
Ejemplos de Algoritmos
Ejemplos de AlgoritmosEjemplos de Algoritmos
Ejemplos de Algoritmos
 

Similar to El algoritmo a (asterisco)

Solución de problemas mediante busqueda
Solución de problemas mediante busquedaSolución de problemas mediante busqueda
Solución de problemas mediante busquedasacrilegetx
 
Inteligencia Artificial - Leonys B
Inteligencia Artificial - Leonys BInteligencia Artificial - Leonys B
Inteligencia Artificial - Leonys BJose Andres
 
Presentación OR Problemas de Caminos Más Cortos
Presentación OR Problemas de Caminos Más CortosPresentación OR Problemas de Caminos Más Cortos
Presentación OR Problemas de Caminos Más CortosRosa E Padilla
 
Mpinning Gy Alg9(Conteo)
Mpinning Gy Alg9(Conteo)Mpinning Gy Alg9(Conteo)
Mpinning Gy Alg9(Conteo)Spimy
 
20 algoritmos
20 algoritmos20 algoritmos
20 algoritmosdiego
 
Introducción a la Inteligencia Artificial_2007.ppt
Introducción a la Inteligencia Artificial_2007.pptIntroducción a la Inteligencia Artificial_2007.ppt
Introducción a la Inteligencia Artificial_2007.pptpedro montilla
 
RAÍCES DE ECUACIONES
RAÍCES DE ECUACIONESRAÍCES DE ECUACIONES
RAÍCES DE ECUACIONESJenny López
 
Implementaciones PHub ABH Búsquedas No Constructivas
Implementaciones PHub ABH Búsquedas No ConstructivasImplementaciones PHub ABH Búsquedas No Constructivas
Implementaciones PHub ABH Búsquedas No Constructivasedmodi
 
Slideshare nelson rodriguez
Slideshare nelson rodriguezSlideshare nelson rodriguez
Slideshare nelson rodrigueznelro038
 
Tecnicas de Busqueda en IA
Tecnicas de Busqueda en IATecnicas de Busqueda en IA
Tecnicas de Busqueda en IARafaelVargas155
 
Reconocimiento unidad 2
Reconocimiento unidad 2Reconocimiento unidad 2
Reconocimiento unidad 2Diego Perdomo
 
SOLUCION DE ECUACIONES NO LINEALES
SOLUCION DE ECUACIONES NO LINEALESSOLUCION DE ECUACIONES NO LINEALES
SOLUCION DE ECUACIONES NO LINEALESJagg602
 

Similar to El algoritmo a (asterisco) (20)

Algoritmo a
Algoritmo aAlgoritmo a
Algoritmo a
 
Grafos 0
Grafos 0Grafos 0
Grafos 0
 
Algoritmo a*
Algoritmo a*Algoritmo a*
Algoritmo a*
 
Solución de problemas mediante busqueda
Solución de problemas mediante busquedaSolución de problemas mediante busqueda
Solución de problemas mediante busqueda
 
Inteligencia Artificial - Leonys B
Inteligencia Artificial - Leonys BInteligencia Artificial - Leonys B
Inteligencia Artificial - Leonys B
 
Presentación OR Problemas de Caminos Más Cortos
Presentación OR Problemas de Caminos Más CortosPresentación OR Problemas de Caminos Más Cortos
Presentación OR Problemas de Caminos Más Cortos
 
Mpinning Gy Alg9(Conteo)
Mpinning Gy Alg9(Conteo)Mpinning Gy Alg9(Conteo)
Mpinning Gy Alg9(Conteo)
 
20 algoritmos
20 algoritmos20 algoritmos
20 algoritmos
 
Informe
InformeInforme
Informe
 
Introducción a la Inteligencia Artificial_2007.ppt
Introducción a la Inteligencia Artificial_2007.pptIntroducción a la Inteligencia Artificial_2007.ppt
Introducción a la Inteligencia Artificial_2007.ppt
 
Flujo en redes
Flujo en redesFlujo en redes
Flujo en redes
 
RAÍCES DE ECUACIONES
RAÍCES DE ECUACIONESRAÍCES DE ECUACIONES
RAÍCES DE ECUACIONES
 
Implementaciones PHub ABH Búsquedas No Constructivas
Implementaciones PHub ABH Búsquedas No ConstructivasImplementaciones PHub ABH Búsquedas No Constructivas
Implementaciones PHub ABH Búsquedas No Constructivas
 
Slideshare nelson rodriguez
Slideshare nelson rodriguezSlideshare nelson rodriguez
Slideshare nelson rodriguez
 
Tecnicas de Busqueda en IA
Tecnicas de Busqueda en IATecnicas de Busqueda en IA
Tecnicas de Busqueda en IA
 
Reconocimiento unidad 2
Reconocimiento unidad 2Reconocimiento unidad 2
Reconocimiento unidad 2
 
SOLUCION DE ECUACIONES NO LINEALES
SOLUCION DE ECUACIONES NO LINEALESSOLUCION DE ECUACIONES NO LINEALES
SOLUCION DE ECUACIONES NO LINEALES
 
Unidad 6 metodos
Unidad 6 metodosUnidad 6 metodos
Unidad 6 metodos
 
Raices deecuaciones
Raices deecuacionesRaices deecuaciones
Raices deecuaciones
 
S4-SCBC.pptx
S4-SCBC.pptxS4-SCBC.pptx
S4-SCBC.pptx
 

El algoritmo a (asterisco)

  • 1. 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
  • 2. 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).
  • 3. 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
  • 4. 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 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’)
  • 5. 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 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.
  • 6. 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.
  • 7. 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.
  • 8. 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. 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 nodo evaluado a cerrados. de todos sus hijos, los inserta en abiertos, y pasa el
  • 9. 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. 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 que para cualquier nodo es consistente (o monótona), es decir, 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.
  • 10. 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*. 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 ._MEJORNODO caso . = . perteneciente a )-----( si g(.) < g(.) entonces // nos quedamos con el camino de menor coste .:= MEJORNODO actualizar g(.) y f'(.) eliminar . añadir . a ._MEJORNODO caso . 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 := []
  • 11. 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 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.
  • 12. 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. 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
  • 13. 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í. 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
  • 14. 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 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.