← Retour au menu des cours

Algorithme A* ("A-étoile" ou "A-star" en anglais)

Summary

Description de l’algorithme

Entrée :

Sortie :
Le plus court chemin entre le sommet initial et le sommet objectif

Idée principale

L’algorithme A* est une amélioration de Dijkstra.

Au lieu de choisir simplement le sommet avec la plus petite distance connue, on choisit le sommet qui minimise :

f(n)=g(n)+h(n) f(n) = g(n) + h(n)

où :

Dijkstra est un cas particulier de A* avec h(n)=0h(n) = 0.

Condition importante

Pour que A* garantisse un plus court chemin, l’heuristique doit être :

0h(n)vraie distance jusqu’au but 0 \leq h(n) \leq \text{vraie distance jusqu’au but}

Un exemple classique est la distance à vol d’oiseau pour un GPS :

L'algorithme

Initialisation

g(n)=+ g(n) = +\infty

On crée :

À chaque étape

  1. On choisit dans la liste ouverte le sommet avec le plus petit f(n)=g(n)+h(n)f(n) = g(n) + h(n)
  2. S’il s’agit du but → on s’arrête
  3. Sinon :
    • On l’enlève de futurs_sommets
    • On l’ajoute à deja_visite
    • Pour chacun de ses voisins :
      • On calcule : gnouveau=g(courant)+couˆt(courant,voisin) g_{\text{nouveau}} = g(\text{courant}) + \text{coût}(\text{courant}, \text{voisin})
      • Si cette nouvelle distance est meilleure :
        • On met à jour g(voisin)g(\text{voisin})
        • On mémorise le parent (pour reconstruire le chemin)
        • On ajoute le voisin à futurs_sommets

Remarques

Comparaison avec Dijkstra

Algorithme Utilise une heuristique ? Explore beaucoup de nœuds ?
Dijkstra Non Oui
A* Oui Beaucoup moins si heuristique efficace

Complexité

Dans le pire cas :

O(bd) O(b^d)

bb est le nombre maximal d'arrêtes sortantes d'un point et dd est le nombre d'arrêtes reliant le sommet initial du sommet final.

Mais en pratique, A* est beaucoup plus rapide si l’heuristique est bonne.

Code en Python

def a_etoile(matrice, depart, arrivee, heuristique):
    n = len(matrice)
    
    g = [float("inf")] * n
    f = [float("inf")] * n
    parent = [None] * n
    
    g[depart] = 0
    f[depart] = heuristique[depart]
    
    futurs_sommets = [(f[depart], depart)]
    
    deja_visite = set() # C'est une liste sans répétitions
    
    while futurs_sommets:
        courant = futurs_sommets.pop()
        
        if courant == arrivee:
            break
        
        if courant in deja_visite:
            continue
            
        deja_visite.add(courant)
        
        for voisin in range(n):
            if matrice[courant][voisin] != float("inf"):
                
                nouveau_g = g[courant] + matrice[courant][voisin]
                
                if nouveau_g < g[voisin]:
                    g[voisin] = nouveau_g
                    f[voisin] = g[voisin] + heuristique[voisin]
                    parent[voisin] = courant
                    
                    futurs_sommets.append((f[voisin], voisin))
    
    # Reconstruction du chemin
    chemin = []
    sommet = arrivee
    while sommet is not None:
        chemin.append(sommet)
        sommet = parent[sommet]
    
    chemin.reverse()
    
    return chemin, g[arrivee]