Formation I.S.N.

Représentation avec la matrice d'adjacence

Reprenons le graphe suivant dans lequel nous souhaitons déterminer le parcours le plus court menant du sommet A au sommet G.

Exemple Graphe

Une autre possibilité pour représenter un graphe avec Python est d'utiliser une matrice (ou liste bidimensionnelle). Cela revient en fait à construire sa matrice d'adjacence, c'est-à-dire la matrice dont le coefficient \( a_{ij} \) est égal à la pondération de l'arête menant du sommet \( i \) au sommet \( j \).

Dans ces conditions les sommets ne seront plus repérés par leur nom mais par un nombre compris entre \( 0 \) et \( n-1 \), où \( n \) est l'ordre du graphe. Il faut donc préalablement décider d'une convention d'association entre le nom du sommet et son numéro dans la matrice. Quand c'est possible, l'ordre alphabétique est privilégié.

Proposition d'un script

Ce script met en oeuvre l'algorithme de Moore-Dijkstra en donnant la longueur de chacun des chemins issus du sommet A et allant vers les autres sommets


def moore_dijkstra_2 (M, s):
    inf = sum(sum(ligne) for ligne in M) + 1
    nb_sommets = len(M)
    s_explore = {s : [0, [s]]}
    #On associe au sommet d'origine s la liste [longueur, plus court chemin]
    s_a_explorer = {j : [inf, ""] for j in range(nb_sommets) if j != s}
    #On associe à chaque sommet j à explorer la liste [longueur, sommet précédent]
    for suivant in range(nb_sommets):
        if M[s][suivant]:
            s_a_explorer[suivant] = [M[s][suivant], s]
            
    print("Dans le graphe d\'origine {} de matrice d\'adjacence :".format(s))
    for ligne in M:
       print(ligne)
    print()
    print("Plus courts chemins de")
    
    while s_a_explorer and any(s_a_explorer[k][0] < inf for k in s_a_explorer):
        s_min = min(s_a_explorer, key = s_a_explorer.get)
        longueur_s_min, precedent_s_min = s_a_explorer[s_min]
        for successeur in range(nb_sommets):
            if M[s_min][successeur] and successeur in s_a_explorer:
                dist = longueur_s_min + M[s_min][successeur]
                if dist < s_a_explorer[successeur][0]:
                    s_a_explorer[successeur] = [dist, s_min]
        s_explore[s_min] = [longueur_s_min, s_explore[precedent_s_min][1] + [s_min]]
        del s_a_explorer[s_min]
        print("longueur", longueur_s_min, ":", " -> ".join(map(str, s_explore[s_min][1])))
        
    for k in s_a_explorer:
        print("Il n\'y a pas de chemin de {} à {}".format(s, k))
        
    return s_explore

maMatrice = [[0, 2, 1, 0, 0, 0, 0],
             [2, 0, 2, 1, 3, 0, 0],
             [1, 2, 0, 4, 3, 5, 0],
             [0, 1, 4, 0, 3, 6, 5],
             [0, 3, 3, 3, 0, 1, 0],
             [0, 0, 5, 6, 1, 0, 2],
			 [0, 0, 0, 5, 0, 2, 0]]
             
moore_dijkstra_2(maMatrice, 0)
	

Pour s'entraîner



  1. Modifier le script ci-dessus pour faire afficher le sommet sélectionné, le plus court chemin depuis le sommet d'entrée ainsi que les dictionnaires s_explore et s_a_explorer à chaque tour de la boucle while. Cela permettra de se rendre compte de l'évolution de ces deux listes au cours du processus.
    • Piste ?
    • Solution ?

    Insérer des fonctions print au bon endroit.

    
    def moore_dijkstra_2 (M, s):
        inf = sum(sum(ligne) for ligne in M) + 1
        nb_sommets = len(M)
        s_explore = {s : [0, [s]]}
        #On associe au sommet d'origine s la liste [longueur, plus court chemin]
        s_a_explorer = {j : [inf, ""] for j in range(nb_sommets) if j != s}
        #On associe à chaque sommet j à explorer la liste [longueur, sommet précédent]
        for suivant in range(nb_sommets):
            if M[s][suivant]:
                s_a_explorer[suivant] = [M[s][suivant], s]
                
        print("Dans le graphe d\'origine {} de matrice d\'adjacence :".format(s))
        for ligne in M:
           print(ligne)
        print()
        
        while s_a_explorer and any(s_a_explorer[k][0] < inf for k in s_a_explorer):
            s_min = min(s_a_explorer, key = s_a_explorer.get)
            longueur_s_min, precedent_s_min = s_a_explorer[s_min]
            for successeur in range(nb_sommets):
                if M[s_min][successeur] and successeur in s_a_explorer:
                    dist = longueur_s_min + M[s_min][successeur]
                    if dist < s_a_explorer[successeur][0]:
                        s_a_explorer[successeur] = [dist, s_min]
            s_explore[s_min] = [longueur_s_min, s_explore[precedent_s_min][1] + [s_min]]
            del s_a_explorer[s_min]
            print()
            print("On a sélectionné le sommet {}".format(s_min))
            print("Plus courts chemins de longueur", longueur_s_min, ":", " -> ".join(map(str, s_explore[s_min][1])))
            print("La nouvelle liste des sommets explorés est : ")
            print(s_explore)
            print("La nouvelle liste des sommets à explorer est : ")
            print(s_a_explorer)
            print()
            
        for k in s_a_explorer:
            print("Il n\'y a pas de chemin de {} à {}".format(s, k))
            
        return s_explore
    
    maMatrice = [[0, 2, 1, 0, 0, 0, 0],
                 [2, 0, 2, 1, 3, 0, 0],
                 [1, 2, 0, 4, 3, 5, 0],
                 [0, 1, 4, 0, 3, 6, 5],
                 [0, 3, 3, 3, 0, 1, 0],
                 [0, 0, 5, 6, 1, 0, 2],
    			 [0, 0, 0, 5, 0, 2, 0]]
                 
    moore_dijkstra_2(maMatrice, 0)
    						


  2. Modifier le script ci-dessus pour laisser à l'utilisateur le choix du sommet d'entrée et du sommet de sortie et pour obtenir le plus court chemin entre ces deux sommets. On veillera à structurer le script convenablement.
    • Piste ?
    • Solution ?

    Ajouter une fonction entree_sortie prenant en argument le graphe, le sommet d'entrée et le sommet de sortie choisis par l'utilisateur.

    
    #---FONCTION QUI CALCULE TOUS LES PLUS COURTS CHEMINS DE L'ENTREE A CHACUN DES SOMMETS-------
    
    def moore_dijkstra_1(G, s):
        inf = sum(sum(G[sommet][i] for i in G[sommet]) for sommet in G) + 1
            #On considère comme "infini" un majorant de la somme de toutes les
            #pondérations du graphe
        global s_explore
        global s_a_explorer
        s_explore = {s : [0, [s]]}
            #On associe au sommet d'origine s la liste [longueur, plus court chemin]
        s_a_explorer = {j : [inf, ""] for j in G if j != s}
            #On associe à chaque sommet j à explorer la liste [longueur, sommet précédent]
        for suivant in G[s]:
            s_a_explorer[suivant] = [G[s][suivant], s]
        
        print("Dans le graphe d\'origine {} dont les arcs sont :".format(s))
        for k in G:
            print(k, ":", G[k])
        print()
        
        #On créé une boucle qui tourne tant que la liste des sommets à explorer contient
        #des points tels que la longueur provisoire calculée depuis l'origine est
        #inférieure à l'infini
        while s_a_explorer and any(s_a_explorer[k][0] < inf for k in s_a_explorer):
            s_min = min(s_a_explorer, key = s_a_explorer.get)
            longueur_s_min, precedent_s_min = s_a_explorer[s_min]
            for successeur in G[s_min]:
                if successeur in s_a_explorer:
                    dist = longueur_s_min + G[s_min][successeur]
                    if dist < s_a_explorer[successeur][0]:
                        s_a_explorer[successeur] = [dist, s_min]
            s_explore[s_min] = [longueur_s_min, s_explore[precedent_s_min][1] + [s_min]]
            del s_a_explorer[s_min]
    
        return s_explore
    
    
    #---------------------FONCTION QUI DEMANDE L'ENTREE ET LA SORTIE DU GRAPHE------------------
    
    def entree_sortie(M, entree, sortie):
        moore_dijkstra_2(M, entree)
        for k in s_explore:
            if sortie == k:
                print("Le plus court chemin menant de {} à {} est {} ".format(entree, sortie, s_explore[k][1]))
                print("Son poids est égal à {}".format(s_explore[k][0]))
        
        for k in s_a_explorer:
            if sortie == k:
                print("Il n\'existe aucun chemin de {} à {}".format(entree, sortie))
    
        
    
    
    #-------------------------------------------PROGRAMME PRINCIPAL------------------------------
    
    MonGraphe = {
        'A':{'B':2, 'C':1},
        'B':{'A':2, 'C':2, 'D':1, 'E':3},
        'C':{'A':1, 'B':2, 'D':4, 'E':3, 'F':5},
        'D':{'B':1, 'C':4, 'E':3, 'F':6, 'G':5},
        'E':{'B':3, 'C':3, 'D':3, 'F':1},
        'F':{'C':5, 'D':6, 'E':1, 'G':2},
        'G':{'D':5, 'F':2}
        }
    
    entree = input("Quel est votre sommet d'entrée ? ")
    sortie = input("Quel est votre sommet de sortie ? ")
    print()
    entree_sortie(MonGraphe, entree, sortie)