Académique Documents
Professionnel Documents
Culture Documents
PISSARRO PONTOISE
2022-2023
Bases des graphes, plus courts chemins
2 Graphe orienté 2
5 Piles, files 4
5.1 Les piles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5.2 Les files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5.3 Le module deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
9 Graphe pondéré 7
1
1 Exemples
RATP, SNCF, EDF, Réseau routier, Facebook, Web, Google Maps, · · ·
2 Graphe orienté
3 1 5
7 6
G = (S, A) avec S = {1, 2, 3, 4, 5, 6, 7} et A = {(1, 7), (7.1), (7, 2), (1, 2), (7, 4), (3, 1), (5, 6), (6, 5)}
On peut représenter G par sa liste d’adjacence :
1 → [2, 7], 2 → [ ], 3 → [1], 4 → [ ], 5 →
[6], 6 → [5], 7 → [1, 2,4]
0 1 0 0 0 0 1
0 0 0 0 0 0 0
1 0 0 0 0 0 0
ou par sa matrice d’adjacence : M = 0 0 0 0 0 0 0
0 0 0 0 0 1 0
0 0 0 0 1 0 0
1 1 0 1 0 0 0
Vocabulaire
graphe orienté : couple (S, A) ou S est un ensemble fini non vide et A un ensemble de couples
d’éléments de S
sommet (ou nœud) : élément de S
arc (ou arête orientée) : élément de A
boucle : arc de la forme (x, x)
degré entrant d’un sommet s : nombre d’arcs qui arrivent à ce sommet, (c’est à dire nombre d’arcs
de la forme (x, s), notation : d− (s)
degré sortant d’un sommet s : nombre d’arcs qui partent de ce sommet, (c’est à dire nombre d’arcs
de la forme (s, x), notation : d+ (s)
chemin d’un sommet à un autre : suite de sommets s0 , s1 , · · · , sp tels que pour tout i ∈ J1, pK,
(ai−1 , ai ) ∈ A
cycle : chemin s0 , s1 , · · · , sp avec s0 = sp
listes d’adjacence : pour chaque sommet s, on donne la liste des sommets où arrive un arc partant
de s (liste des successeurs de s)
matrice d’adjacence : si S = J1, nK, matrice M = (mij ) ∈ Mn (R) avec mij = 1 si (i, j) ∈ A et
mij = 0 sinon.
7 6
2
G = (S, A) avec S = {1, 2, 3, 4, 5, 6, 7} et A = {{7, 1}, {7, 2}, {1, 2}, {7, 4}, {3, 1}, {5, 6}, }
On peut représenter G par sa liste d’adjacence :
1 → [2, 3, 7], 2 → [1, 7], 3 → [1], 4 → [7],
5 → [6], 6 → [5], 7 →[1, 2, 4],
0 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 0
ou par sa matrice d’adjacence : M = 0 0 0 0 0 0 1
0 0 0 0 0 1 0
0 0 0 0 1 0 0
1 1 0 1 0 0 0
Vocabulaire
graphe non orienté : couple (S, A) ou S est un ensemble fini non vide et A un ensemble de paires
d’éléments de S (deux à deux distincts)
sommet (ou nœud) : élément de S
arête : élément de A
degré d’un sommet s : nombre d’arêtes d’extrémité ce sommet, (c’est à dire nombre d’arêtes de la
forme {x, a}, notation : d(s)
chemin d’un sommet à un autre : suite de sommets s0 , s1 , · · · , sp tels que pour tout i ∈ J1, pK,
{ai−1 , ai } ∈ A
connexité dans les graphes non orientés : on dit qu’un graphe non orienté est connexe quand deux
sommets quelconques sont reliés par un chemin.
listes d’adjacence : pour chaque sommet s, on donne la liste des voisins de s
matrice d’adjacence : si S = J1, nK, matrice M = (mij ) ∈ Mn (R) avec mij = 1 si {i, j} ∈ A et
mij = 0 sinon. M est une matrice symétrique.
2 2
4 4
7 6 7 6
3
[[0,1,0,0,0,0,1],[0,0,0,0,0,0,1],[1,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,1,0],[0,0,0,0,1,0,0],[1,1,0,1,0,0,0]]
5 Piles, files
5.1 Les piles
• Structure de type LIFO (Last In First Out)
• Opérations
◦ Créer une pile vide
◦ Ajouter (empiler) un élément
◦ Enlever et retourner un élément (dépiler)
◦ Tester si une pile est vide
• Python : implémentation par une liste
◦ Créer une pile vide : P = []
◦ Ajouter (empiler) un élément a : P.append(a)
◦ Enlever et retourner un élément (dépiler) : x = P.pop()
◦ Tester si une pile est vide : if P == []
Toutes ces opérations se font en temps constant (indépendant de la longueur de la liste) donc
efficacité.
4
if len(F) != 0:
print(F.popleft())
7 6
Utilisation de piles
from collections import deque
LA = {1:[2,3,7],2:[6,5],3:[4],4:[],5:[6],6:[5],7:[1,2,4]}
def parcours(listeAdj,s):
""" parcours du graphe à partir du sommet s"""
# création du dictionnaire vu
vu = {}
for sommet in listeAdj:
vu[sommet] = False
# création de la pile ou de la file aTraiter
aTraiter = deque()
aTraiter.append(s)
vu[s] = True
while len(aTraiter)>0:
sommet = aTraiter.pop() # utilisation de piles
for voisin in listeAdj[sommet]:
if not vu[voisin]:
aTraiter.append(voisin)
vu[voisin] = True
Utilisation de files
Comment modifier le programme précédent pour utiliser les files ?
Files : parcours en largeur
Piles : parcours en profondeur
5
7 Application à la détection de la connexité d’un graphe non orienté
3 1 5 3 1 5
2 2
4 4
7 6 7 6
On parcours le graphe à partir du sommet 1, si on voit tous les sommets, le graphe est connexe, sinon, il
ne l’est pas.
L1 = {1:[2,3,7],2:[1,7],3:[1],4:[7],5:[6],6:[5],7:[1,2,4]}
L2 = {1:[2,3,7],2:[1,5,6,7],3:[1],4:[7],5:[2,6],6:[2,5],7:[1,2,4]}
def estConnexe(listeAdj):
"""retourne True si le graphe est connexe et False sinon"""
# liste des sommets du graphe
S = list(listeAdj.keys())
# création du dictionnaire vu
vu = {}
for sommet in S:
vu[sommet] = False
# création de la pile ou de la file aTraiter
aTraiter = deque()
aTraiter.append(S[0])
vu[S[0]] = True
while len(aTraiter) > 0:
sommet = aTraiter.pop()
for voisin in listeAdj[sommet]:
if not vu[voisin]:
aTraiter.append(voisin)
vu[voisin] = True
for x in S:
if not vu[x]:
return False
return True
print(estConnexe(L1))
print(estConnexe(L2))
7 6
6
On parcourt le graphe en largeur (utilisation d’une file) à partir du sommet 1. On rajoute un dictionnaire
dist qui donne la distance de chaque sommet au sommet de départ. Quand on visite un sommet s, on
affecte à chacun de ses successeurs non encore visité la distance dist[s]+1
Le sommet 1 est à la distance 0.
Ensuite, on traite tous ses successeurs, ils sont à la distance 1.
Ensuite, on traite tous les successeurs non encore vus des précédents, ils sont à la distance 2.
Et ainsi de suite.
LA = {1:[2,3,4,7],2:[5,6,7],3:[4],4:[7],5:[6],6:[5],7:[1,2,4,6]}
def distances(listeAdj,s):
""" détermine les distances minimum de chaque sommet au sommet s
retourne un dictionnaire qui à chaque sommet associe sa distance à s"""
# création du dictionnaire vu
vu = {}
for sommet in listeAdj:
vu[sommet] = False
# création du dictionnaire des distances
dist = {}
for sommet in listeAdj:
dist[sommet] = float(’inf’) # flottant de valeur +infini
dist[s] = 0
# création de la pile ou de la file aTraiter
aTraiter = deque()
aTraiter.append(s)
vu[s] = True
while len(aTraiter)>0:
sommet = aTraiter.popleft()
for voisin in listeAdj[sommet]:
if not vu[voisin]:
aTraiter.append(voisin)
vu[voisin] = True
dist[voisin] = dist[sommet]+1
return dist
distances(LA,1) donne
{1: 0, 2: 1, 3: 1, 4: 1, 5: 2, 6: 2, 7: 1}
9 Graphe pondéré
3 3 7
3 1 2 5
5 2 7 5
6 2
4
1
7 6
4
G = (S, A, ρ) avec S = {1, 2, 3, 4, 5, 6, 7}, A = {(1, 7), (7.1), (7, 2), (1, 2), (7, 4), (3, 1), (5, 6), (6, 5), (7, 6), (2, 5), (6, 2)}
et ρ l’application de S dans R+ définie par :
(1, 7) 7→ 5, (7.1) 7→ 2, (7, 2) 7→ 6, (1, 2) 7→ 3, (7, 4) 7→ 1, (3, 1) 7→ 3, (5, 6) 7→ 2, (6, 5) 7→ 5, (7, 6) 7→
4, (2, 5) 7→ 7, (6, 2) 7→ 7
On peut représenter G par sa liste d’adjacence :
1 → [(2, 3), (7, 5)], 2 → [(5, 7)], 3 → [(1, 3)], 4 → [ ], 5 → [(6, 2)], 6 → [(5, 5), (2, 7)], 7 → [(1, 2), (2, 6), (4, 1), (6, 4)]
7
0 3 0 0 0 0 5
0 0 0 0 7 0 0
3 0 0 0 0 0 0
0
ou par sa matrice d’adjacence : M = 0 0 0 0 0 0
0 0 0 0 0 2 0
0 7 0 0 5 0 0
2 6 0 1 0 4 0
Vocabulaire
graphe pondéré orienté : triplet (S, A, ρ) ou S est un ensemble fini non vide, A un ensemble de
couples d’éléments de S et ρ une application de S dans R+
poids d’un arc a : ρ(a)
poids d’un chemin : somme des poids des arcs de ce chemin
listes d’adjacence : pour chaque sommet s, on donne la liste des couples (t, p) où t est un sommet
où arrive un arc partant de s (successeurs de s) et p le poids de l’arc (s, t).
matrice d’adjacence : si S = J1, nK, matrice M = (mij ) ∈ Mn (R) avec mij = p si (i, j) est un arc
de poids p et mij = 0 sinon.
5 2 7 5
6 2
4
1
7 6
4
On parcours le graphe à partir du sommet 1. Pour chaque sommet s accessible à partir de 1, on détermine
le poids minimum d’un chemin joignant 1 à s.
Le graphe est donné par sa liste d’adjacence représentée par le dictionnaire :
{ 1:[(2,3),(7,5)], 2:[(5,7)], 3:[(1,3)], 4:[], 5:[(6,2)], 6:[(5,5),(2,7)],
7:[ (1,2),(2,6),(4,1),(6,4)]}
3 variables :
- aTraiter : une liste de couples (s, δ) où les s sont les sommets à traiter et δ le poids associé au
sommet s.
Au début, aTraiter est vide.
- vu : un dictionnaire qui sert à marquer si un sommet a été vu.
vu[s] vaut True si le sommet a été vu et False sinon.
Au début,
vu = { 1:False, 2:False, 3:False, 4:False, 5:False, 6:False, 7:False, }
- R : une liste qui contiendra les résultats.
Au début, R est vide.
• On commence par mettre le sommet 1 dans aTraiter avec la distance 0 :
aTraiter.append((1,0))
8
LA = {1:[(2,3),(7,5)], 2:[(5,7)], 3:[(1,3)], 4:[], 5:[(6,2)], 6:[(5,5),(2,7)],
7:[ (1,2),(2,6),(4,1),(6,4)]}
def minDist(L):
""" L est une liste de couples (s,dist)
la fonction retourne un élément pour lequel dist est le plus petit possible"""
xmin = L[0]
min = xmin[1]
for x in L:
if x[1]<min:
xmin = x
min = xmin[1]
return xmin
def Dijkstra(listeAdj,s):
""" listeAdj est la liste d’adjacence d’un graphe pondéré
pour chaque sommet on calcule la distance minimum de s à t
on retourne le résultat dans une liste"""
#création du dictionnaire vu
vu = {}
for sommet in listeAdj:
vu[sommet] = False
# création de la liste aTraite
aTraiter = [(s,0)]
#creation de la liste des résultats
R = []
while aTraiter != []:
x = minDist(aTraiter) #élément avec une distance minimum
aTraiter = [y for y in aTraiter if y != x] # on enlève cet élément de la liste aTraiter
sommet = x[0] # sommet correspondant
if not vu[sommet]: # si ce sommet n’a pas encore été vu
R.append(x) # on l’ajoute au résultat
delta = x[1] # distance à s correspondant
vu[sommet] = True #on le marque comme vu
for y in listeAdj[sommet]: #on place dans aTraiter tous ses voisins non vus
if not vu[y[0]]:
aTraiter.append((y[0],y[1]+delta))
return R
print(Dijkstra(LA,1))
On trouve
[(1, 0), (2, 3), (7, 5), (4, 6), (6, 9), (5, 10)]