Académique Documents
Professionnel Documents
Culture Documents
Graphe non orienté : Couple G=(S,A) où A est un ensemble d’ensembles {u, v} avec u, v ∈S et
u≠v
2
S: sommets
A: arêtes 1 4
boucles non admises
3
Convention (pour uniformiser les notations) : une arête {u,v} d’un graphe non-orienté est aussi
dénotée (u, v); et (u,v) et (v,u) dénotent la même arête.
Graphe pondéré : graphe G=(S,A) avec une fonction de poids w : A → R
Graphes - définitions de bases
Si G=(S,A) est un graphe (orienté ou non-orienté) et e=(u,v) ∈ A :
2
1 2 3 4
1 4 2 4
3 4
4
3
2
1 2 3 4
1 4 2 1 4
3 1 4
4 1 2 3
3
2
1 2 3 4
1 0 1 1 1
1 4 2 0 0 0 1
3 0 0 0 1
4 0 0 0 0
3
2
1 2 3 4
1 0 1 1 1
1 4 2 1 0 0 1
3 1 0 0 1
4 1 1 1 0
3
( on peut en stocker la moitié )
En cas de poids associé aux arcs/arêtes : M(i,j) stocke le poids de (i,j)
Représentation des graphes
Par listes d'adjacence:
‣ mémoire demandée : O(|S|+|A|)
‣ efficace pour les graphes peu denses ( |A| << |S|2 )
‣ recherche d’un arc/arête (u,v) : parcours de la liste d’adjacence de u
‣ parcours de tous les arcs/arêtes : O(|S|+|A|)
2. a) Quand la file est vide, tout sommet accessible depuis s a été rencontré :
Supposer qu’il existe un sommet accessible t non rencontré quand la file est vide. Sur le
chemin de s à t soit v le premier sommet non rencontré (à partir de s) et soit u son
prédécesseur (u rencontré)
s u v t
- Chaque itération défile un élément après au plus |S| itérations la file est vide
‣ Coût du parcours
‣ Au plus une itération par sommet. Une itération :
- défile le sommet en O(1) et
- parcourt ses sommets adjacents - O(1) sur chaque adjacent
coût :
‣ :
- graphe orienté : chaque arc est examiné au plus une fois : O(|A|)
- graphe non orienté : chaque arête est examiné au plus deux fois : O(|A|)
‣ coût O(|S|+|A|) en supposant représentation par liste d’adjacence
Parcours en largeur - distances
‣ Parcours augmenté avec n’importe quelle opération effectuée sur chaque sommet rencontré
‣ calcul de la distance des sommets du graphe d’un sommet origine
‣ calcul de l’arborescence de parcours en largeur
Distances:
1) Contenu de la file:
a) Si un sommet u est dans la file F u a été rencontré ( i.e. distance[u] ≠-1 ).
b) Les sommets dans la file sont triés par valeur de distance[u] (valeur minimale en tête).
c) Si t est la tête et q est la queue de F : distance[t] ≤ distance[q] ≤ distance[t] +1
2) Si t est la tête de la file, tous les sommets v à distance δ(v)≤ δ(t) ont été rencontrés ( i.e.
distance[v] ≠-1 )
Preuve. Exercice
Lemme.
Soit B l’ensemble des sommets v tels que rencontré[v]= faux au début d’un appel récursif
Parcours-en-profondeur( G, u ) avec u ∈B.
Soir GB le sous-graphe de G engendré par B.
Alors le graphe de parcours en profondeur de l’appel Parcours-en-profondeur( G, u ) est une
arborescence dont la racine est u et les sommets sont exactement les sommets accessibles
depuis u dans GB
‣ Intervalles bien parenthesés : si u et v sont deux sommets, leurs intervalles associés satisfont
une des deux propriétés suivantes :
‣ soit un des intervalles est inclut dans l’autre
‣ soit les deux intervalles sont disjoints (l’un commence après la fin de l’autre)
Recherche en profondeur (Depth First Search)
‣ Recherche en profondeur : parcours en profondeur réitéré jusqu’à ce que tous les sommets
aient été rencontrés.
Recherche-en-profondeur( Graphe G )
initialiser rencontré[ ] à faux π[ ] à nil et date à 0 , allouer d[ ] et f [ ]
Pour tout sommet v de G
si rencontré[v] = faux Parcours-en-profondeur (G, v)
Exemple 1
G 2 3 6 7
4 5
Classifications des arcs
Soit G’ la forêt de parcours en profondeur d’un graphe orienté G
‣ Classification des arcs de G:
‣ arcs de liaison : arcs de G’
‣ arcs avants : arcs (u, v) t.q. v est un descendant propre de u dans G’ et (u,v) n’est pas un arc
de liaison
‣ arcs arrière : arcs (u, v) t.q. v est un ancêtre de u dans G’ (inclut les boucles)
‣ arcs transverses : tous les autres
Exemple 1
arc avant
arc transverse
G 2 3 6 7
on
iais
arc arrière
l
de
4 5
arc
arc transverse
• Alors d(v) < d(u). Deux cas : [ d(v) [ d(u) f(u)] f(v) ] ou [ d(v) f(v) ] [ d(u) f(u)]
• Si [ d(v) [ d(u) f(u)] f(v) ] v ancêtre de u dans l’arborescence en profondeur
(u,v) arc arrière contradiction ☐
Classifications des arêtes
Soit G’ la forêt de parcours en profondeur d’un graphe non-orienté G
‣ Classification des arêtes de G:
‣ arêtes de liaison : arêtes de G’
‣ arêtes arrière : arêtes {u, v} t.q. v est un ancêtre de u dans G’ et {u,v} n’est pas de liaison
Lemme.
Si e est une arête d’un graphe non orienté, e est soit une arête de liaison soit une arête arrière.
Preuve. Soit {u,v} une arête de G,
‣ Supposer sans perte de généralité d[u] < d[v]
‣ rencontré[v] = faux au début du parcours en profondeur de u (v ∈ B)
et v est accessible depuis u dans GB ( par l'arête (u, v) )
v est un sommet de l’arborescence de parcours en profondeur enraciné en u
‣ G acyclique un tri des sommets par f(u) décroissant est un tri topologique
‣ Si G a un circuit.
๏ Soit v le sommet de ce circuit qui est exploré en premier pendant le parcours en
profondeur ( le plus petit d[v] )
๏ Soit u le prédécesseur de v dans le circuit
๏ Si u=v l’arc (u,v) est un arc arrière par définition
๏ Si u≠v alors u n’a pas encore été rencontré à la date d[v]
๏ parcours-en-profondeur(G, v) retourne une arborescence de racine v ayant u comme
descendant propre
๏ (u,v) est un arc arrière
Composantes fortement connexes
‣ Les composantes fortement connexes d’un graphe orienté sont les classes d'équivalence de la
relation ≈ suivante :
u ≈ v ssi u est accessible depuis v et v est accessible depuis u
Lemme. Soit F une une forêt de parcours en profondeur d’un graphe orienté G. Le
sous-graphe de F engendré par chaque composante fortement connexe de G est un arbre
Preuve. Exercice
1 6
F
G 2 3 5 7
4 8
Composantes fortement connexes
‣ On dénote ri le sommet de G qui est racine de sa composante dans F
‣ On suppose r1...rn triés par date de fin f[ri] croissante
‣ On dénote Ci la composante de racine ri
C3
r3
1 6 C1
r2 r1
2 3 5 7
C2 4 8
C3 C2 C1
Composantes fortement connexes
‣ Composantes fortement connexes et parcours en profondeur:
Lemme. Ci est l’ensemble de sommets qui sont descendants de ri en F et n’appartiennent
pas à C1, ..Ci-1.
Preuve.
C3 C1
๏ v∈Ci v descendant de ri et v∉C1, ..., v∉Ci-1. r3
1 6
๏ v descendant de ri
r2 r1
il existe un chemin de ri à v 2 3 5 7
‣ Remarque :
Dans un parcours en profondeur de G, en fin de traitement de ri, les composantes C1...Ci-1
ont déjà été parcourues (composantes qui se terminent avant ri)
Si on suppose C1...Ci-1 déjà calculés, il suffit de détecter que ri est la racine de sa composante
pour calculer Ci
‣ C’est l’idée de l’algorithme de Tarjan pour calculer les composantes fortement connexes
Algorithme de Tarjan
Idée de l’algorithme:
‣ Faire un parcours en profondeur de G et stocker les sommets dans une pile dans l’ordre
dans lequel ils sont rencontrés pour la première fois
‣ Les composantes sont éliminées de la pile au fur et à mesure qu’elles se terminent (à la fin
du traitement de leur racine)
‣ Cela arrive dans l’ordre r1...rn (l’ordre de fin de traitement des racines dans le parcours)
‣ à la fin du traitement de chaque sommet u : détecter si u est une racine
‣ Si u est une racine ri, le sommet de la pile contient tous les descendants de ri sauf les
composantes déjà terminées, i.e les composantes C1, ...Ci-1
le sommet de la pile contient la composante Ci
‣ stocker Ci et éliminer Ci de la pile
‣ Coût : coût d’un parcours en profondeur O(|S|+|A|)
Problème à résoudre :
‣ Détecter, en fin de traitement, si un sommet est une racine d’une composante,
en supposant connues les composantes déjà terminées
Algorithme de Tarjan
Définition ( retour(u) ). Soit u ∈ Ci
๏ Supposer d[w]≥ d[u] d[w]> d[u] (par l’imbrication des intervalles) d[w] > f[u]
๏ d[w] > d[u’] contradiction ( parce que (u’, w) arc arrière ou transverse d[w] ≤ d[u’] )
☐
Algorithme de Tarjan
‣ retour(u) peut être calculé pendant le parcours en profondeur, en fin de traitement de u,
grâce à la caractérisation suivante :
Lemme Soit u ∈ Ci.
retour(u) = min { d[u] } ∪
{ d[v] | (u, v) est un arc arrière ou transverse et v ∉ C1, ..v ∉ Ci-1} ∪
{ retour(v) | (u, v) est un arc de liaison }
Preuve. Exercice
‣ Composantes fortement connexes d’un graphe orienté G :
Tarjan( Graphe G )
initialiser rencontré[ ] à faux et date à 0 ,
allouer d[ ], f[ ] et ret[] // tableaux pour les dates de découverte et fin et les valeurs de retour( )
Pile P; // la pile des sommets rencontrés
Liste L; // la liste des composantes
Pour tout sommet v de G
si rencontré[v] = faux Parcours-Tarjan(G, v)
retourner L;
Algorithme de Tarjan
Parcours-Tarjan( Graphe G, Sommet u )
date ←date+1; d[u] ← date ; rencontré[u] ← vrai ; Empiler(P, u)
ret[u] ← d[u]
for all (u, v) ∈ A
if ( not rencontré[v] ) then // (u,v) arc de liaison
Parcours-Tarjan(G,v) ; ret[u] ← min{ ret[u], ret[v] }
elseif ( rencontré[v] and d[v] < d[u] ) // (u,v) arc arrière ou transverse
si v est dans la pile // i.e. v n’appartient pas au composantes déjà terminés
ret[u] ← min { ret[u], d[v] }
endif
endfor
date ← date+1 ; f[u] ← date
if ( ret[u] = d[u] ) then // u est la racine de sa composante
//composante de u : tous les descendants de u dans la pile
C←∅
repeat x ← sommet(P) ; Dépiler(P); C←C ∪ { x }; until ( x=u )
Inserer-en-tete(L, C)
endif
Validité de l’algorithme de Tarjan
‣ Pre et post-conditions :
๏ Si au début d’un appel récursif Parcours-Tarjan(G, u) la pile contient exactement tous les
sommets v déjà rencontrés ( i.e. d[v] < d[u] ) qui n’appartiennent pas aux composantes
fortement connexes déjà terminées ( i.e avec f[rj]< d[u] ),
à la fin de Parcours-Tarjan(G, u) :
๏ 1) La pile contient exactement tous les sommets v déjà rencontrés (i.e. d[v] < f[u] ) qui
n’appartiennent pas aux composantes fortement connexes déjà terminées (i.e avec f[rj]≤ f[u])
๏ 2) La liste des composantes contient exactement toutes les composantes fortement
connexes déjà terminées ( i.e avec f[rj]≤ f[u] )
๏ 3) ret[u] = retour(u)
Preuve. Exercice
‣ Validité
‣ Pre-condition vrai au début du premier appel Parcours-Tarjan(G, v) effectué par Tarjan(G)
(Pile vide et aucun sommet rencontré)
pre-condition vrai au début de chaque appel Parcours-Tarjan(G, v)
3) Si δ(u, v) est fini et p est un plus court chemin de u à v, chaque sous-chemin de p est un
plus court chemin entre son sommet de départ et son sommet d’arrivé
Algorithme de Bellman-Ford
‣ Input : un graphe orienté pondéré G=(S,A) avec fonction de poids w, un sommet de départ s
‣ Output : - un tableau d[ 1..|S| ] tel que d[u] = δ(s,u) pour tous u ∈ S, s’il n’existe pas de circuit
de poids strictement négatif accessible depuis s
- un booléen qui vaut faux ssi il existe un circuit de poids strictement négatif accessible depuis s
‣ Idée de l’algorithme :
‣ Pour tout v ∈S d[v] est initialisé à une “estimation” de δ(s, v) (borne supérieure)
‣ à chaque itération une meilleure estimation est obtenue pour chaque sommet sur la base
des estimations courantes :
‣ Si (u, v) ∈A d[u] +w(u, v) ≥ δ(s, u) +w(u, v) ≥ δ(s, v)
‣ Si d[u] + w(u, v) ≤ d[v] la nouvelle estimation est meilleure et d[v] ← d[u] +w(u, v)
( relâchement de l’arc (u,v) )
‣ Si aucun circuit de poids strictement négatif n’est accessible depuis s, après |S|-1 itérations les
bornes ne peuvent plus être améliorées (point fixe)
‣ Si il y a un circuit de poids négatif accessible depuis s, le point fixe n’est pas atteint après |S|-1
itérations
Algorithme de Bellman-Ford
Bellman-Ford( Graphe (S,A,w), Sommet s )
//estimation initiale
Pour tout v∈ S d[v] ← ∞
d[s] ← 0
for ( i ← 1 to |S|-1 ) do
Coût O(|S||A|) //relâchement de tous les arcs
pour tout (u,v) ∈ A d[v] ← min{ d[v], d[u]+w(u,v) }
endfor
‣ Calcul des plus courts chemins : calculer un tableau des prédécesseurs π t.q. π[v] est le
prédécesseur de v dans un plus court chemin de s à v, s’il existe
‣ initialiser π[v]←nil pour tout v
‣ à chaque relâchement tel que d[v]← d[u]+w(u,v) affecter π[v]← u
Validité de l’algorithme de Bellman-Ford
Lemme. Dans l’algorithme de Bellmann-Ford, pour tout v ∈ S :
Preuve Exercice
‣ L’algorithme peut être modifié pour retourner d[v] =δ(s,v) pour tout v∈S (Exercice)
Algorithme de Dijkstra
Plus courts chemins dans un graphe orienté où le poids de tous les arcs est positif ou nul
‣ Entrée : un graphe orienté pondéré G=(S,A) avec une fonction de poids w t.q w(e) ≥ 0 ∀ e∈S,
un sommet de départ s
‣ Sortie : un tableau d[ 1..|S| ] tel que d[u] = δ(s,u) pour tous u ∈S
‣ Idée de l’algorithme (approche gloutonne)
‣ pour tout sommet v, d[v] contient toujours une “estimation” de δ(s, v) (borne supérieure)
‣ l’algorithme maintient un ensemble de sommets E t.q. d[v]=δ(s, v) pour tout v∈ E
‣ choix glouton : à chaque étape le sommet u ∈ S\E ayant d[u] minimale est ajouté à E
(d[u]=δ(s, u)) et ses arcs sortant sont relâchés.
E x y
- poids positifs ou nuls w(p) ≥ w(ps↝y) ≥ d[y]
- d[u] > δ(s, u) = w(p) ≥ d[y] contradiction (u est le sommet de S\E avec d[u] minimal)
d[u] n’est pas modifié avant la fin de l'itération i ( min{ d[u], d[u] +w(u,u) } = d[u] )
au début de l'itération i+1 d[v] = δ(s,v) pour tout v ∈ E
Validité de l’algorithme de Dijkstra
➡ 4) Au début de l'itération i+1, pour tout v ∈ S\E :
‣ remarque : v ≠s
‣ si v n’est pas un successeur de u , d[v] n’a pas été modifié par l'itération i
- d[v] = δE\{u} (s, v) (par 4)
- δE\{u} (s, v) = δE(s, v) ( u n’est pas un prédécesseur de v )
‣ si v est un successeur de u d[v] = min{ δE\{u} (s, v), d[u] +w(u, v) }
- d[u] = δ(s, u) d[u] + w(u, v) = δ{u}(s, v)
i n j
plus court chemin de n à j avec
plus court chemin de i à n avec
sommets intermédiaires
sommets intermédiaires
dans {1,...,n-1}
dans {1,...,n-1}
‣ Sous-problèmes :
Soit δk(i, j) la longueur du plus court chemin de i à j avec sommets intermédiaires dans {1,..,k}
δk(i, j) = min { δk-1(i, j), δk-1(i, k) + δk-1(k, j) }
w(i,j) si i≠j
δ0(i, j) =
0 si i=j
‣ Calcul des plus court chemins : calculer un tableau des prédécesseurs π[1..n, 1..n],
à l'itération k, à π[i,j] est affecté le prédécesseur de j dans un plus court chemin de i à j dont
les sommets intermédiaires sont dans {1..k} :
‣ initialiser π[i,j] ← i si i≠j et w(i,j) <∞ et π[i,j] ← NIL, sinon
‣ à l'itération k, pour tout i, j, avant le calcul de d[i,j] :
if( d[i,j] > d[i,k]+d[k,j] ) π[i,j] ←π[k,j] endif
Algorithme de Floyd-Warshall - Exercice
En présence de cycles de poids strictement négatif :
w(i,j) si i≠j
‣ Définir Δ0(i, j) =
min{ 0, w(i,j) } si i=j
‣ Pour tout i, j ∈ S
Si p est un chemin simple de i à j dont les sommets intermédiaires sont tous dans {1..k} (p
est un cycle simple si i=j) Δk(i, j) ≤ w(p)
‣ Démontrer ensuite le lemme suivant
Lemme. Pour tout i, j ∈S δ(i,j) = -∞ ssi il existe un sommet k∈S tel que
τk(i,j) : vrai ssi il existe un chemin de i à j dont les sommets intermédiaires sont dans {1..k}
0 si i≠j et (i,j) ∉A
τ0(i, j) =
1 si i=j ou (i,j)∈A
๏ Coût Θ(n3)
๏ Approche directe plus efficace (tableaux de bits, opérations booléennes plus efficaces)
Arbres couvrants minimaux
Arbre couvrant minimal
Soit G=(S, A) un graphe connexe non-orienté muni d’une fonction w de poids des arêtes.
‣ Arbre couvrant de G : sous-graphe T=(S, A’) avec A’ ⊆ A, tel que A est un arbre (i.e. un graphe
non-orienté connexe et acyclique).
‣ Remarque : |A’| =|S|-1
‣ Poids d’un sous-graphe T=(S,A’) : .
9 8
w(T) = 22
7
Arbres couvrants minimaux et algorithmes gloutons
Calcul d’un arbre couvrant minimal d’un graphe non-orienté pondéré connexe G=(S,A) :
‣ Réduction au calcul d’un ensemble optimal d’un matroïde pondéré
‣ instance de l’algorithme glouton pour les matroïdes pondérés : O(|A|2)
‣ Approches gloutonnes directes plus efficaces
‣ Algorithme de Kruskal :
‣ à l’aide d’une structure de données union-find : O(|A| log |A| )
‣ à l’aide d’une structure union-find optimisée + tri en temps linéaire : O( |A| log*|S| )
‣ Algorithme de Prim
‣ à l’aide d’un tas binaire : O( |A| log|S| )
‣ à l’aide d’un tas de Fibonacci : O( |S| log |S| + |A| )
Remarque dans un graphe non-orienté connexe |A| ≥ |S| -1
‣ Kruskal/union-find et Prim/tas binaire : même coût asymptotique
‣ Prim/tas de Fibonacci : plus performant
Arbres couvrants minimaux et algorithmes gloutons
‣ Idée de l’approche gloutonne :
----
Initialiser un ensemble E à ∅
Soit (P, S\P) une partition de S (appelé coupure) telle qu’aucune arête de E ne traverse la coupure
( i.e. pour toute arête (u,v) de E soit {u,v} ⊆ P soit {u,v} ⊆ S\P ).
Soit (u,v) l'arête de poids minimal qui traverse la coupure (P, S\P). Alors E ∪ {(u,v)} est contenu
dans un arbre couvrant minimal de G.
➡
3
2 6
4 P
5
8
E
9 8
7
S\P
Arbres couvrants minimaux et algorithmes gloutons
Preuve du théorème.
‣ Soit T=(S,A’) l’arbre couvrant minimal de G qui contient E.
‣ Si T contient l'arête minimale (u,v) qui traverse la coupure terminé.
‣ Supposer que T ne contient pas (u,v) : (u,v) crée un cycle dans T avec l’unique chemin γ qui
relie u et v dans T
‣ u ∈P, v∈ S\P il existe une arête (x,y) de γ u v
qui traverse la coupure
‣ (x,y) ∉ E P S\P
γ
‣ T’ :=(S, A’’) avec A’’ = A’ \ {(x,y)} ∪ {(u,v)}
x y
‣ E ⊆ A’ et (x,y) ∉ E E⊆ A’’ E ∪{(u,v)} ⊆ A’’
E←∅
endwhile
return E
3 C
E
5
8
9 8
7
6
Algorithme de Kruskal
‣ Choix de la coupure : P = une composante connexe de (S,E)
Remarque : dans l’algorithme générique, tant que |E| <|S|-1, le graphe (S,E) n’est pas connexe
‣ E ne traverse pas la coupure
‣ Plus précisément :
๏ chaque étape choisit l'arête e de poids minimal qui relie deux composantes connexes de E
e
3 C
E
5
8
9 8
7
S\C 6
๏ e est aussi l'arête de poids minimal qui traverse la coupure (C, S\C)
Algorithme de Kruskal
‣ Pour mémoriser les composantes connexes de E et rechercher efficacement la composante
d’un sommet : structure union-find
----------
Kruskal ( Graphe (S,A, w) )
E←∅
Pour tout v ∈ S creer-ensemble (v) ; // les composantes connexes initiales de E (les singletons)
endwhile
return E
-----------
‣ La correction dérive de la correction de l’algorithme générique et du choix de l'arête minimale
‣ La séquence d'arêtes de E peut être trouvée en une seule passe sur A trié par poids croissant
Algorithme de Kruskal
Kruskal ( Graphe (S,A, w) )
E←∅
Pour tout v ∈ S creer-ensemble (v) ; // les composantes connexes initiales de (S,E) (les singletons)
endif
endfor
return E
5
E
8
‣ prédécesseur d’un sommet v∈S\P : un sommet u∈P tel que w(u,v) = coût de v
‣ À chaque étape le sommet à coût minimal de S\P est inséré dans P (et les coûts mis à jour)
‣ E est représenté implicitement : E={ (u, pred(u)) | u ∈ P et pred(u) ≠ nil }
‣ P est également représenté implicitement : S\P est stocké dans une file de priorité
Algorithme de Prim
Prim ( Graphe (S,A,w) )
// initialement P est vide tous les coûts sont ∞
Pour tout v∈ S c[v] ← ∞; π[v] ← NIL
choisir un sommet s
c[s] ←0
// S\P est stocké dans une file de priorité F :
F ← Creer-File-Priorité ( S ) // priorité de v : c[v]
while ( not Est-File-Vide(F) ) do
u ← Défiler-min(F); // u est implicitement inséré dans P
pour tout (u,v) ∈ A
3) |E| =|P| -1
Preuve : Exercice
‣ Correction de l’algorithme de Prim
On montre qu’il est une instance de l’algorithme générique :
‣ Par A) E est initialement vide
‣ Par l’invariant 1) à chaque itération (P, S\P) est une coupure qui n’est pas traversée par E
‣ Par l’invariant 2) chaque itération insère dans E l'arête minimale qui traverse (P, S\P)
‣ À la fin de la dernière itération F=∅ P=S (par 3.) |E|=|S|-1
Coût de l’algorithme de Prim
(Même analyse que pour l’algorithme de Dijkstra, mais sur un graphe connexe |S| =O(|A|) )
‣ Opérations :
‣ Création d’une file de priorité contenant |S| éléments
‣ |S| opérations d’extraction du minimum
‣ |A| opérations de réduction de la priorité
( test v∈F en temps constant : maintenir un tableau de booléens )
Définition. Un réseau de transport est un graphe orienté G=(S,A) sans boucle avec
deux sommets particuliers, la source s ∈ S et le puits t ∈ S, et une fonction de capacité
c : S×S → R t.q. :
1. Si (u,v)∈ A c(u,v) ≥0 et si (u,v) ∉ A c(u,v) =0
Valeur du flot : 6
|f| = 6
2 6
2 8
(le flot net sortant de la source) 2
s 5 t
2 2 4
6 1
5 1
3
|f| = 7
3
Problème du flot maximal : donné un réseau de transport, trouver le flot de valeur maximale
Le problème du flot maximal
Sans perte de généralité, le réseau G n’a pas d’arcs “anti-parallèles” (u,v) et (v,u)
‣ Chaque réseau avec arcs anti-parallèles peut être transformé en un réseau sans arcs anti-
parallèles qui est équivalent pour le problème du flot maximal
G G’
c
c c' c'
Pour chaque flot f sur G il existe un flot f’ sur G’ avec |f’|=|f| et vice-versa
Réseau résiduel
Soit G=(S,A) un réseau de transport de fonction de capacité c. Soit f un flot sur G
Capacité résiduelle cf : S×S → R
‣ La capacité résiduelle de u à v représente les unités de flot qui peuvent encore être envoyées
sur la connexion de u à v :
8
‣ Si (u,v) ∈ A cf (u,v) = c(u,v) - f(u,v) u v cf (u,v) = 5
3
‣ Remarque : la capacité résiduelle est bien définie parce que soit (u,v) ∈ A soit (v,u) ∈ A
Réseau résiduel pour G et f : Gf =(S, Af) Af={ (u,v) ∈ S×S | cf(u,v) >0 }, capacité cf
2 8
3
|f| = 5 s 5 t
2 4
6 1
3
3
3
1
Gf
5
3
2 5
1
s 5 t
2 3
3 1
3
3
Chemin améliorants
‣ (u,v) dans Gf cf (u,v) unités supplémentaires de flot peuvent être envoyées de u à v sur G
1 5
5 6
3 2 5
2 2 8
5 3-1
1 5
5
2 3 2 1 4
s 3 1 t s 6 1 t
3 3+1 1
3 3
3
Gf G, f’ |f’|=|f|+1
Lemme. Si f est un flot sur G et p est un chemin de s à t dans Gf alors f+fp est un flot sur G de
valeur |f|+|fp| > |f|
retourner f
Correction
‣ À chaque étape f est un flot sur G de valeur strictement croissante (par le lemme sur les
chemins améliorants)
‣ En supposant que l’algorithme termine, il faut démontrer que :
s’il n’existe pas de chemin améliorant dans Gf f est un flot maximal sur G
5
6
2 5
2 8
3
c(E,T) = 9 s 5 t f(E,T) = 5
2 4
6 1
3
3
3
Flot net de X à Y :
‣ Remarque :
‣ Conservation du flot : f ( {v}, S ) = 0 pour tout v ∈ S\{s,t}
‣ Valeur du flot : |f| = f ( {s}, S )
‣ Propriétés du flot net:
1) f (X,X) = 0
2) f (X,Y) = - F(Y,X)
3) Si X1 ∩ X2 =∅ f (X1 ∪ X2, Y) = f (X1,Y) + f (X2,Y)
‣ Capacités rationnelles : multiplier toutes les capacités par un facteur capacités entières
‣ Propriétés de l’algorithme :
Soit f et f’ les flots avant et après une itération de l’algorithme d’Edmonds-Karp sur G=(S,A).
Soit p le chemin améliorant choisi par l'itération.
1) Si (u,v) est un arc critique de p, (u,v) est absent de Gf’
- si (u,v) ∈ A
cf (u,v) = c(u,v) - f(u,v) et f’(u,v) = f(u,v) + cf (u,v) = c(u,v) cf’ (u,v) = c(u,v) - f’(u,v) = 0
2) Si (u,v) est absent de Gf et (u,v) est présent dans Gf’ , alors p contient (v,u)
‣ Si (u,v) ∈ A cf(u,v) = 0 f(u,v) = c(u,v)
cf’(u,v) > 0 f’(u,v) < c(u,v) f’(u,v) < f(u, v) (v, u) ∈ p
Par l’absurde
➡ Soit v le sommet à δf’ (s,v) minimal tel que δf’ (s,v) < δf (s,v) ( v ≠ s et δf’ (s,v) doit être fini)
➡ Soit γ le plus court chemin de s à v dans Gf’, et soit u le prédécesseur de v dans γ
δf’ (s,u) = δf’ (s,v)-1
δf’ (s,u) ≥ δf (s,u)
(sinon v ne serait pas le sommet à δf’ (s,v) minimal dont la distance a été diminuée)
➡ (u,v) est absent de Gf :
( sinon δf (s,v) ≤ δf (s,u) +1 ≤ δf’ (s,u)+1 = δf’ (s,v) )
➡ p = plus court chemin de s a t dans Gf il existe un plus court chemin s ↝↝v→ u dans Gf
Preuve
‣ On démontre que pour tout (u,v) ∈ A∪A-, (u,v) peut devenir critique au plus |S|/2 fois
➡ Entre deux itérations qui rendent un même arc (u,v) critique, la distance de u depuis
s dans le réseau résiduel augmente d’au moins 2