



Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
cours et exercice des Graphs en python
Typology: Exercises
1 / 5
This page cannot be seen from the preview
Don't miss anything!




On rappelle qu’un graphe pondéré (orienté par exemple) est représenté en python de 3 manières différentes :
On peut écrire une fonction qui prend en entrée une liste de sommets et une liste d’arrêtes (une liste de liste donc) d’un graphe non orienté et renvoie le dictionnaire associé à la liste d’adjacence.
def adja(S,A): ’’’ fonction qui prend en entrée une liste de sommets et une liste de listes (arrêtes du graphe) et r (A : list, S : list)--> (dico : dict)’’’ dico={} for sommet in S : dico[sommet]=[] for arrete in A: s1,s2,pond=arrete[0],arrete[1],arrete[2] dico[s1].append([s2,pond]) #dico[s2].append([s1,pond]) à rajouter si le graphe est non orienté) return dico
On peut aussi écrire une fonction qui prend en entrée deux listes S et A tel que (S, A) représente un graphe non orienté et renvoie la matrice d’adjacence associée. Et faire de même dans le cas où le graphe est représenté par un dictionnaire (qui représente sa liste d’adjacence).
def matriceadja(S,A) : n=len(S) mat=[[0 for _ in range(n) ] for _ in range(n) ] trad={} k= for sommet in S : trad[sommet]=k k=k+ for arrete in A: s1,s2=trad[arrete[0]],trad[arrete[1]] mat[s1][s2]=arrete[2] #mat[s2][s1]=arrete[2] return mat
def matriceadja(D) : key=D.keys() n=len(key) mat=[[0 for _ in range(n) ] for _ in range(n) ] trad={} k= for sommet in key :
trad[sommet]=k k=k+ for sommet in key: for voisin in D[sommet]: s1=trad[sommet] s2=trad[voisin[0]] mat[s1][s2]=voisin[1] #mat[s2][s1]=voisin[1] return mat
On rappelle ici les algorithmes de parcours en profondeur et en largeur, dans le cas d’un graphe pondéré.
On utilise la structure de pile : from collections import deque def parcoursprof_it(graphe,sommet): visite=[] marque={} attente=deque() attente.append(sommet) while len(attente)>0: sommet=attente.pop() if sommet not in marque : visite.append(sommet) marque[sommet]= for vois in graphe[sommet]: if vois[0] not in marque: attente.append(vois[0]) return visite
On utilise la structure de file : from collections import deque def parcourslargeur_it(graphe,sommet): visite=[] marque={} attente=deque() attente.append(sommet) while len(attente)>0: sommet=attente.popleft() if sommet not in marque : visite.append(sommet) marque[sommet]= for vois in graphe[sommet]: if vois[0] not in marque: attente.append(vois[0]) return visite
on suppose dans cette partie que le graphe est connexe. L’objectif de cette partie est de construire un algorithme pour trouver le plus court chemin entre deux sommets dans un graphe pondéré orienté (ou non). Pour cela, on utilise un algorithme glouton qui repose sur le principe suivant : si dans un graphe pondéré,
d={k : float(’inf’) for k in G} d[s]= while len(d)>0: som=mini(d) for vois in G[som]: voisin,dist=vois[0],vois[1] if voisin not in D : d[voisin] = min(d[voisin] , d[som] + dist) D[som]=d[som] del d[som] return D
Analyse rapide : La terminaison est évidente, un variant de boucle étant tk la taille du dictionnaire d à l’étape k de la boucle while. La complexité est dans le pire des cas en O(n^2 ) où n est le nombre de sommet (n étapes dans la boucle while et moins de n étapes dans la boucle for). Remarque : il suffit de modifier la condition d’arrêt par while fin in d pour que l’algorithme s’arrête quand l’on sait la distance minimal de s à f in
Nous allons chercher un algorithme qui permet de trouver "un court chemin" entre deux sommets par une méthode heuristique. L’idée d’une méthode heuristique est de donner un algorithme qui renvoie une solution non optimale mais convenable et qui est obtenu en un temps raisonnable (ce qui est très utile dans les cas où aucun algorithme optimal n’est de complexité raisonnable). Nous avons déjà mis en oeuvre ce principe dans le cadre des algorithmes "gloutons". Pour cela, nous allons utiliser une fonction h, dont les données sont issues d’informations extérieures, qui prend en entrée un sommet s du graphe et renvoie un flottant (ou un entier) positif. Cette fonction "rajoutera" à chaque étape une pondération pour le choix du sommet prioritaire : l’idée étant d’éliminer des sommets qui semble (d’après les données extérieurs) inutile : on peut pour cela utiliser une "distance à vol d’oiseau" comme dans l’exemple ci-dessous, ou un nombre correspondant à une estimation du nombre de sommets à parcourir (comme dans l’exercice de fin), etc ....
def mini2(dico): ’’’ au moins une des valeurs du dico ne doit pas être inf ’’’ m=float(’inf’) for s in dico.keys() : d=dico[s][0]+dico[s][1] if d < m : m=d minimum=s return minimum
def astar(G,deb,fin,h): ’’’G est un graphe pondéré sous la forme d’un dictionnaire représentant sa liste d’adjacence, et s un D={} d={k : [float(’inf’),h(k)] for k in G} d[deb]=[0,h(deb)] while fin in d: print(d) som=mini2(d) for vois in G[som]: voisin,dist=vois[0],vois[1] if voisin not in D : d[voisin][0] = min(d[voisin][0] , d[som][0] + dist) D[som]=d[som] del d[som] return D[fin][0]
Réalisons l’exemple suivant : on considère la graphe donnée par sa liste d’adjacence :
def heur(s): val_heur={’A’:9,’B’:7,’C’:8,’D’:8,’E’:0,’F’:6,’G’:3,’H’:6,’I’:4 , ’J’:4 , ’K’:3 , ’L’:6 , ’S’:10} return val_heur[s]
print(dijkstra(G,’S’),astar(G,’S’,’E’,heur))
Exercice 1 : Avec un de vos voisins, donnez un graphe orienté pondéré de au moins 6 sommets et de au moins 10 arcs. Réaliser chacun de votre côté l’algorithme de Dijkstra et comparer vos résultats. Exercice 2 : En utilisant la fonction dijkstra, écrire une fonction qui prend en entrée un graphe non pondéré connexe et un sommet s et renvoie un dictionnaire dont les clefs sont les sommets k du graphe et les valeurs le nombre minimal d’arcs à parcourir pour aller de s à k. Exercice 3 : Pour le graphe qui suit, appliquer à la main l’algorithme de Dijkstra pour obtenir le chemin le plus court reliant les sommets R1 et R6. Faire de même avec l’algorithme A star en utilisant l’heuristique : la valeur associée à un sommet est 3 fois le nombre d’arrêtes nécessaires pour atteindre ce sommet (on suppose ce nombre connu et on le multiplie par trois car on suppose que la longueur moyenne d’une arrête est 3). Le graphe est donné par sa liste d’adjacence :
G={ ’R1’ : [[’R2’,2],[’R3’,2],[’R4’,3]], ’R2’ : [[’R1’,1],[’R4’,4],[’R7’,4]], ’R3’ : [[’R1’,2],[’R5’,5],[’R4’,2]], ’R4’ : [[’R1’,3],[’R2’,4],[’R3’,2],[’R6’,4],[’R7’,5]], ’R5’ : [[’R3’,5],[’R6’,4]], ’R6’ : [[’R4’,4],[’R4’,4],[’R7’,3]], ’R7’ : [[’R2’,4],[’R5’,5],[’R6’,3]], }