Skip to content
Snippets Groups Projects
Verified Commit a2e0cbb2 authored by orestis.malaspin's avatar orestis.malaspin
Browse files

added 2024

parent ff338371
Branches master
No related tags found
No related merge requests found
---
title: "Théorie des graphes"
date: "2024-05-21"
---
# Les graphes
\Huge
Les graphes
# Les graphes! Historique
**Un mini-peu d'histoire...**
## L. Euler et les 7 ponts de Koenigsberg:
* Existe-t-il une promenade sympa, passant **une seule fois** par les 7 ponts et revenant au point de départ?
![Les ponts c'est beau. Source: Wikipédia, <https://bit.ly/37h0yOG>](figs/Konigsberg_bridges.png){width=50%}
. . .
* Réponse: ben non!
# Utilisation quotidienne
## Réseau social
![Source, Wikipedia: <https://bit.ly/3kG6cgo>](figs/Social_Network.svg){width=40%}
* Chaque sommet est un individu.
* Chaque trait une relation d'amitié.
* Miam, Miam, Facebook.
# Utilisation quotidienne
## Moteurs de recherche
![Source, Wikipedia: <https://bit.ly/3kG6cgo>](figs/PageRanks-Example.svg){width=40%}
* Sommet est un site.
* Liens sortants;
* Liens entrants;
* Notion d'importance d'un site: combien de liens entrants, pondérés par l'importance du site.
* Miam, Miam, Google (PageRank).
# Introduction
## Définition, plus ou moins
* Un graphe est un ensemble de sommets, reliés par des lignes ou des flèches.
![Deux exemples de graphes.](figs/ex_graphes.png)
* Des sommets (numérotés 1 à 6);
* Connectés ou pas par des traits ou des flèches!
# Généralités
## Définitions
* Un **graphe** $G(V, E)$ est constitué
* $V$: un ensemble de sommets;
* $E$: un ensemble d'arêtes.
* Une **arête** relie une **paire** de sommets de $V$.
## Remarques
* Il y a **au plus** une arête $E$ par paire de sommets de $V$.
* La **complexité** d'un algorithme dans un graphe se mesure en terme de $|E|$ et $|V|$, le nombre d'éléments de $E$ et $V$ respectivement.
# Généralités
## Notations
* Une arête d'un graphe **non-orienté** est représentée par une paire **non-ordonnée** $(u,v)=(v,u)$, avec $u,v\in V$.
* Les arêtes ne sont pas orientées dans un graphe non-orienté (elles sont bi-directionnelles, peuvent être parcourues dans n'importe quel ordre).
## Exemple
::: columns
:::: column
![Un graphe non-orienté.](figs/ex_graphe_non_oriente.svg)
::::
:::: column
## Que valent $V$, $|V|$, $E$, et $|E|$?
. . .
\begin{align*}
V&=\{1, 2, 3, 4\},\\
|V|&=4,\\
E&=\{(1,2),(2,3),(2,4),(4,1)\},\\
|E|&=4.
\end{align*}
::::
:::
# Généralités
## Notations
* Une arête d'un graphe **orienté** est représentée par une paire **ordonnée** $(u,v)\neq(v,u)$, avec $u,v\in V$.
* Les arêtes sont orientées dans un graphe orienté (étonnant non?).
## Exemple
::: columns
:::: column
![Un graphe orienté.](figs/ex_graphe_oriente.svg)
::::
:::: column
## Que valent $V$, $|V|$, $E$, et $|E|$?
. . .
\begin{align*}
V&=\{1, 2, 3, 4\},\\
|V|&=4,\\
E&=\{(1,2),(2,3),(2,4),(4,1),(4,2)\},\\
|E|&=5.
\end{align*}
::::
:::
# Généralités
## Définition
* Le somme $v$ est **adjacent** au sommet $u$, si et seulement si $(u,v)\in E$;
* Si un graphe non-orienté contient une arête $(u,v)$, $v$ est adjacent à $u$ et $u$ et adjacent à $v$.
## Exemple
::: columns
:::: column
![Sommet $a$ adjacent à $c$, $c$ adjacent à $a$.](figs/ex_adj_non_or.svg){width=80%}
::::
:::: column
![Sommet $a$ adjacent à $c$.](figs/ex_adj_or.svg){width=80%}
::::
:::
# Généralités
## Définition
* Un **graphe pondéré** ou **valué** est un graphe dont chaque arête a un
poids associé, habituellement donné par une fonction de pondération $w:E\rightarrow\mathbb{R}$.
## Exemples
![Graphe pondéré orienté (gauche) et non-orienté (droite).](figs/ex_graph_pond.pdf){width=80%}
# Généralités
## Définition
* Dans un graphe $G(V,E)$, une **chaîne** reliant un sommet $u$ à un sommet $v$ est une suite d'arêtes entre les sommets, $w_0$, $w_1$, ..., $w_k$, telles que
$$
(w_i, w_{i+1})\in E,\quad u=w_0,\quad v=w_k,\quad \mbox{pour }0\leq i< k,
$$
avec $k$ la longueur de la chaîne (le nombre d'arêtes du chemin).
## Exemples
![Illustration d'une chaîne, ou pas chaîne dans un graphe.](figs/ex_graphe_chaine.pdf){width=80%}
# Généralités
## Définition
* Une **chaîne élémentaire** est une chaîne dont tous les sommets sont distincts, sauf les extrémités qui peuvent être égales
## Exemples
![Illustration d'une chaîne élémentaire.](figs/ex_graphe_chaine_elem.pdf){width=80%}
# Généralités
## Définition
* Une **boucle** est une arête $(v,v)$ d'un sommet vers lui-même.
## Exemples
![Illustration d'une boucle.](figs/ex_graphe_boucle.pdf){width=40%}
# Généralités
## Définition
* Un graphe non-orienté est dit **connexe**, s'il existe un chemin reliant n'importe quelle paire de sommets distincts.
## Exemples
\
::: columns
:::: column
![Graphe connexe. Source, Wikipédia: <https://bit.ly/3yiUzUv>](figs/graphe_connexe.svg){width=80%}
::::
:::: column
![Graphe non-connexe avec composantes connexes. Source, Wikipédia: <https://bit.ly/3KJB76d>](figs/composantes_connexes.svg){width=60%}
::::
:::
# Généralités
## Définition
* Un graphe orienté est dit **fortement connexe**, s'il existe un chemin reliant n'importe quelle paire de sommets distincts.
## Exemples
\
::: columns
:::: column
![Graphe fortement connexe.](figs/ex_graph_fort_connexe.pdf){width=60%}
::::
:::: column
![Composantes fortement connexes. Source, Wikipédia: <https://bit.ly/3w5PL2l>](figs/composantes_fortement_connexes.svg){width=100%}
::::
:::
# Généralités
## Définition
* Un **cycle** dans un graphe *non-orienté* est une chaîne de longueur $\geq 3$ telle que le 1er sommet de la chaîne est le même que le dernier, et dont les arêtes sont distinctes.
* Pour un graphe *orienté* on parle de **circuit**.
* Un graphe sans cycles est dit **acyclique**.
## Exemples
![Illustration de cycles, ou pas.](figs/ex_graphe_cycle.pdf){width=100%}
# Question de la mort
* Qu'est-ce qu'un graphe connexe acyclique?
. . .
* Un arbre!
# Représentations
* La complexité des algorithmes sur les graphes s'expriment en fonction du nombre de sommets $V$, et du nombre d'arêtes $E$:
* Si $|E|\sim |V|^2$, on dit que le graphe est **dense**.
* Si $|E|\sim |V|$, on dit que le graphe est **peu dense**.
* Selon qu'on considère des graphes denses ou peu denses, différentes structure de données peuvent être envisagées.
## Question
* Comment peut-on représenter un graphe informatiquement? Des idées (réflexion de quelques minutes)?
. . .
* Matrice/liste d'adjacence.
# Matrice d'adjacence
* Soit le graphe $G(V,E)$, avec $V=\{1, 2, 3, ..., n\}$;
* On peut représenter un graphe par une **matrice d'adjacence**, $A$, de dimension $n\times n$ définie par
$$
A_{ij}=\left\{ \begin{array}{ll}
1 & \mbox{si } i,j\in E,\\
0 & \mbox{sinon}.
\end{array} \right.
$$
::: columns
:::: column
## Exemple
```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
1---2;
1---4;
2---5;
4---5;
5---3;
```
::::
:::: column
\footnotesize
## Quelle matrice d'adjacence?
. . .
```
|| 1 | 2 | 3 | 4 | 5
===||===|===|===|===|===
1 || 0 | 1 | 0 | 1 | 0
---||---|---|---|---|---
2 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
3 || 0 | 0 | 0 | 0 | 1
---||---|---|---|---|---
4 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
5 || 0 | 1 | 1 | 1 | 0
```
::::
:::
# Matrice d'adjacence
## Remarques
* Zéro sur la diagonale.
* La matrice d'un graphe non-orienté est symétrique
$$
A_{ij}=A_{ji}, \forall i,j\in[1,n]
$$.
::: columns
:::: column
```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
1---2;
1---4;
2---5;
4---5;
5---3;
```
::::
:::: column
\footnotesize
```
|| 1 | 2 | 3 | 4 | 5
===||===|===|===|===|===
1 || 0 | 1 | 0 | 1 | 0
---||---|---|---|---|---
2 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
3 || 0 | 0 | 0 | 0 | 1
---||---|---|---|---|---
4 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
5 || 0 | 1 | 1 | 1 | 0
```
::::
:::
# Matrice d'adjacence
* Pour un graphe orienté (digraphe)
::: columns
:::: column
## Exemple
```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
2-->1;
1-->4;
2-->5;
5-->2;
4-->5;
5-->3;
```
::::
:::: column
\footnotesize
## Quelle matrice d'adjacence?
. . .
```
|| 1 | 2 | 3 | 4 | 5
===||===|===|===|===|===
1 || 0 | 0 | 0 | 1 | 0
---||---|---|---|---|---
2 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
3 || 0 | 0 | 0 | 0 | 0
---||---|---|---|---|---
4 || 0 | 0 | 0 | 0 | 1
---||---|---|---|---|---
5 || 0 | 1 | 1 | 0 | 0
```
::::
:::
* La matrice d'adjacence n'est plus forcément symétrique
$$
A_{ij}\neq A_{ji}.
$$
# Stockage
* Quel est l'espace nécessaire pour stocker une matrice d'adjacence pour un graphe orienté?
. . .
* $\mathcal{O}(|V|^2)$.
* Quel est l'espace nécessaire pour stocker une matrice d'adjacence pour un graphe non-orienté?
. . .
* $\mathcal{O}(|V|-1)|V|/2$.
# Considérations d'efficacité
* Dans quel type de graphes la matrice d'adjacence est utile?
. . .
* Dans les graphes denses.
* Pourquoi?
. . .
* Dans les graphes peu denses, la matrice d'adjacence est essentiellement composée de `0`.
## Remarque
* Dans la majorité des cas, les grands graphes sont peu denses.
* Comment représenter un graphe autrement?
# La liste d'adjacence (non-orienté)
* Pour chaque sommet $v\in V$, stocker les sommets adjacents à $v$-
* Quelle structure de données pour la liste d'adjacence?
. . .
* Tableau de liste chaînée, vecteur (tableau dynamique), etc.
::: columns
:::: column
## Exemple
![Un graphe non-orienté.](figs/ex_graph_adj.pdf){width=80%}
::::
:::: column
## Quelle liste d'adjacence?
. . .
![La liste d'adjacence.](figs/ex_graph_list_adj.pdf)
::::
:::
# La liste d'adjacence (orienté)
::: columns
:::: column
## Quelle liste d'adjacence pour...
* Matrix (2min)
```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
0-->1;
0-->2;
1-->2;
3-->0;
3-->1;
3-->2;
```
::::
:::: column
```
```
::::
:::
# Complexité
## Stockage
* Quelle espace est nécessaire pour stocker une liste d'adjacence (en fonction de $|E|$ et $|V|$)?
. . .
$$
\mathcal{O}(|E|)
$$
* Pour les graphes *non-orientés*: $\mathcal{O}(2|E|)$.
* Pour les graphes *orientés*: $\mathcal{O}(|E|)$.
## Définition
* Le **degré** d'un sommet $v$, est le nombre d'arêtes incidentes du sommet (pour les graphes orientés on a un degré entrant ou sortant).
* Comment on retrouve le degré de chaque sommet avec la liste d'adjacence?
. . .
* C'est la longueur de la liste chaînée.
# Parcours
* Beaucoup d'applications nécessitent de parcourir des graphes:
* Trouver un chemin d'un sommet à un autre;
* Trouver si le graphe est connexe;
* Il existe *deux* parcours principaux:
* en largeur (Breadth-First Search);
* en profondeur (Depth-First Search).
* Ces parcours créent *un arbre* au fil de l'exploration (si le graphe est non-connexe cela crée une *forêt*, un ensemble d'arbres).
# Illustration: parcours en largeur
![Le parcours en largeur.](figs/parcours_larg.pdf){width=80%}
# Exemple
## Étape par étape (blanc non-visité)
![Initialisation.](figs/parcours_larg_0.pdf){width=50%}
## Étape par étape (gris visité)
![On commence en `x`.](figs/parcours_larg_1.pdf){width=50%}
# Exemple
## Étape par étape
![On commence en `x`.](figs/parcours_larg_1.pdf){width=50%}
## Étape par étape (vert à visiter)
![Vister `w`, `t`, `y`.](figs/parcours_larg_2.pdf){width=50%}
# Exemple
## Étape par étape
![Vister `w`, `t`, `y`.](figs/parcours_larg_2.pdf){width=50%}
## Étape par étape
![`w`, `t`, `y` visités. `u`, `s` à visiter.](figs/parcours_larg_3.pdf){width=50%}
# Exemple
## Étape par étape
![`w`, `t`, `y` visités. `u`, `s` à visiter.](figs/parcours_larg_3.pdf){width=50%}
## Étape par étape
![`u`, `s`, visités. `r` à visiter.](figs/parcours_larg_4.pdf){width=50%}
# Exemple
## Étape par étape
![`u`, `s`, visités. `r` à visiter.](figs/parcours_larg_4.pdf){width=50%}
## Étape par étape
![`r` visité. `v` à visiter.](figs/parcours_larg_5.pdf){width=50%}
# Exemple
## Étape par étape
![`r` visité. `v` à visiter.](figs/parcours_larg_5.pdf){width=50%}
## Étape par étape
![The end. Plus rien à visiter!](figs/parcours_larg_6.pdf){width=50%}
# En faisant ce parcours...
::: columns
:::: column
## Du parcours de l'arbre
![](figs/parcours_larg_6.pdf){width=100%}
::::
:::: column
## Quel arbre est créé par le parcours (2min)?
. . .
```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
0[x]-->1[w];
0-->2[t];
0-->3[y];
2-->9[u];
1-->4[s];
4-->5[r];
5-->6[v];
```
::::
:::
## Remarques
* Le parcours dépend du point de départ dans le graphe.
* L'arbre sera différent en fonction du noeud de départ, et de l'ordre de parcours des voisins d'un noeud.
# Le parcours en largeur
## L'algorithme, idée générale (3min, matrix)?
. . .
```C
v = un sommet du graphe
i = 1
pour sommet dans graphe et sommet non-visité
visiter(v, sommet, i) // marquer sommet à distance i visité
i += 1
```
## Remarque
* `i` est la distance de plus cours chemin entre `v` et les sommets en cours de visite.
# Le parcours en largeur
## L'algorithme, pseudo-code (3min, matrix)?
* Comment garder la trace de la distance?
. . .
* Utilisation d'une **file**
. . .
```C
initialiser(graphe) // tous sommets sont non-visités
file = visiter(sommet, vide) // sommet est un sommet du graphe au hasard
tant que !est_vide(file)
v = défiler(file)
file = visiter(v, file)
```
## Que fait visiter?
```
file visiter(sommet, file)
sommet = visité
pour w = chaque arête de sommet
si w != visité
file = enfiler(file, w)
retourne file
```
# Exercice (5min)
## Appliquer l'algorithme sur le graphe
![](figs/parcours_larg_0.pdf){width=50%}
* En partant de `v`, `s`, ou `u` (par colonne de classe).
* Bien mettre à chaque étape l'état de la file.
# Complexité du parcours en largeur
## Étape 1
* Extraire un sommet de la file;
## Étape 2
* Traîter tous les sommets adjacents.
## Quelle est la complexité?
. . .
* Étape 1: $\mathcal{O}(|V|)$,
* Étape 2: $\mathcal{O}(2|E|)$,
* Total: $\mathcal{O}(|V| + |2|E|)$.
# Exercice
* Établir la liste d'adjacence et appliquer l'algorithme de parcours en largeur au graphe
```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
1---2;
1---3;
1---4;
2---3;
2---6;
3---6;
3---4;
3---5;
4---5;
```
# Illustration: parcours en profondeur
![Le parcours en profondeur. À quel parcours d'arbre cela ressemble-t-il?](figs/parcours_prof.pdf){width=80%}
# Parcours en profondeur
## Idée générale
* Initialiser les sommets comme non-lus
* Visiter un sommet
* Pour chaque sommet visité, on visite un sommet adjacent s'il est pas encore visité récursivement.
## Remarque
* La récursivité est équivalent à l'utilisation d'une **pile**.
# Parcours en profondeur
## Pseudo-code (5min)
. . .
```C
initialiser(graphe) // tous sommets sont non-visités
pile = visiter(sommet, vide) // sommet est un sommet du graphe au hasard
tant que !est_vide(pile)
v = dépiler(pile)
pile = visiter(v, pile)
```
## Que fait visiter?
. . .
```C
pile visiter(sommet, pile)
sommet = visité
pour w = chaque arête de sommet
si w != visité
pile = empiler(pile, w)
retourne pile
```
# Exercice
* Établir la liste d'adjacence et appliquer l'algorithme de parcours en profondeur au graphe
```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
1---2;
1---3;
1---4;
2---3;
2---6;
3---6;
3---4;
3---5;
4---5;
```
# Interprétation des parcours
* Un graphe vu comme espace d'états (sommet: état, arête: action);
* Labyrinthe;
* Arbre des coups d'un jeu.
. . .
* BFS (Breadth-First) ou DFS (Depth-First) parcourent l'espace des états à la recherche du meilleur mouvement.
* Les deux parcourent *tout* l'espace;
* Mais si l'arbre est grand, l'espace est gigantesque!
. . .
* Quand on a un temps limité
* BFS explore beaucoup de coups dans un futur proche;
* DFS explore peu de coups dans un futur lointain.
# Contexte: les réseaux (informatique, transport, etc.)
* Graphe orienté;
* Source: sommet `s`;
* Destination: sommet `t`;
* Les arêtes ont des poids (coût d'utilisation, distance, etc.);
* Le coût d'un chemin est la somme des poids des arêtes d'un chemin.
## Problème à résoudre
* Quel est le plus court chemin entre `s` et `t`.
# Exemples d'application de plus court chemin
## Devenir riches!
* On part d'un tableau de taux de change entre devises.
* Quelle est la meilleure façon de convertir l'or en dollar?
![Taux de change.](figs/taux_change.pdf){width=80%}
. . .
* 1kg d'or => 327.25 dollars
* 1kg d'or => 208.1 livres => 327 dollars
* 1kg d'or => 455.2 francs => 304.39 euros => 327.28 dollars
# Exemples d'application de plus court chemin
## Formulation sous forme d'un graphe: Comment (3min)?
![Taux de change.](figs/taux_change.pdf){width=80%}
# Exemples d'application de plus court chemin
## Formulation sous forme d'un graphe: Comment (3min)?
![Graphes des taux de change.](figs/taux_change_graphe.pdf){width=60%}
* Un sommet par devise;
* Une arête orientée par transaction possible avec le poids égal au taux de change;
* Trouver le chemin qui maximise le produit des poids.
. . .
## Problème
* On aimerait plutôt avoir une somme...
# Exemples d'application de plus court chemin
## Conversion du problème en plus court chemin
* Soit `taux(u, v)` le taux de change entre la devise `u` et `v`.
* On pose `w(u,w)=-log(taux(u,v))`
* Trouver le chemin poids minimal pour les poids `w`.
![Graphe des taux de change avec logs.](figs/taux_change_graphe_log.pdf){width=60%}
* Cette conversion se base sur l'idée que
$$
\log(u\cdot v)=\log(u)+\log(v).
$$
# Applications de plus courts chemins
## Quelles applications voyez-vous?
. . .
* Déplacement d'un robot;
* Planificaiton de trajet / trafic urbain;
* Routage de télécommunications;
* Réseau électrique optimal;
* ...
# Plus courts chemins à source unique
* Soit un graphe, $G=(V, E)$, une fonction de pondération $w:E\rightarrow\mathbb{R}$, et un sommet $s\in V$
* Trouver pour tout sommet $v\in V$, le chemin de poids minimal reliant $s$ à $v$.
* Algorithmes standards:
* Dijkstra (arêtes de poids positif seulement);
* Bellman-Ford (arêtes de poids positifs ou négatifs, mais sans cycles).
* Comment résoudre le problèmes si tous les poids sont les mêmes?
. . .
* Un parcours en largeur!
# Algorithme de Dijkstra
## Comment chercher pour un plus court chemin?
. . .
```
si distance(u,v) > distance(u,w) + distance(w,v)
on passe par w plutôt qu'aller directement
```
# Algorithme de Dijkstra (1 à 5)
* $D$ est le tableau des distances au sommet $1$: $D[7]$ est la distance de 1 à 7.
* Le chemin est pas forcément direct.
* $S$ est le tableau des sommets visités.
::: columns
:::: column
![Initialisation.](figs/dijkstra_0.png)
::::
:::: column
. . .
![1 visité, `D[2]=1`, `D[4]=3`.](figs/dijkstra_1.png)
::::
:::
# Algorithme de Dijkstra (1 à 5)
::: columns
:::: column
![Plus court est 2.](figs/dijkstra_1.png)
::::
:::: column
. . .
![2 visité, `D[3]=2`, `D[7]=3`.](figs/dijkstra_2.png)
::::
:::
# Algorithme de Dijkstra (1 à 5)
::: columns
:::: column
![Plus court est 3.](figs/dijkstra_2.png)
::::
:::: column
. . .
![3 visité, `D[7]=3` inchangé, `D[6]=6`.](figs/dijkstra_3.png)
::::
:::
# Algorithme de Dijkstra (1 à 5)
::: columns
:::: column
![Plus court est 4 ou 7.](figs/dijkstra_3.png)
::::
:::: column
. . .
![4 visité, `D[7]=3` inchangé, `D[5]=9`.](figs/dijkstra_4.png)
::::
:::
# Algorithme de Dijkstra (1 à 5)
::: columns
:::: column
![Plus court est `7`.](figs/dijkstra_4.png)
::::
:::: column
. . .
![7 visité, `D[5]=7`, `D[6]=6` inchangé.](figs/dijkstra_5.png)
::::
:::
# Algorithme de Dijkstra (1 à 5)
::: columns
:::: column
![Plus court est 6.](figs/dijkstra_5.png)
::::
:::: column
. . .
![`6` visité, `D[5]=7` inchangé.](figs/dijkstra_6.png)
::::
:::
# Algorithme de Dijkstra (1 à 5)
::: columns
:::: column
![Plus court est 5 et c'est la cible.](figs/dijkstra_6.png)
::::
:::: column
. . .
![The end, tous les sommets ont été visités.](figs/dijkstra_7.png)
::::
:::
# Algorithme de Dijkstra
## Idée générale
* On assigne à chaque noeud une distance $0$ pour $s$, $\infty$ pour les autres.
* Tous les noeuds sont marqués non-visités.
* Depuis du noeud courant, on suit chaque arête du noeud vers un sommet non visité et on calcule le poids du chemin à chaque voisin et on met à jour sa distance si elle est plus petite que la distance du noeud.
* Quand tous les voisins du noeud courant ont été visités, le noeud est mis à visité (il ne sera plus jamais visité).
* Continuer avec le noeud à la distance la plus faible.
* L'algorithme est terminé losrque le noeud de destination est marqué comme visité, ou qu'on a plus de noeuds qu'on peut visiter et que leur distance est infinie.
# Algorithme de Dijkstra
## Pseudo-code (5min, matrix)
\footnotesize
. . .
```C
tab dijkstra(graph, s, t)
pour chaque v dans graphe
distance[v] = infini
q = ajouter(q, v)
distance[s] = 0
tant que non_vide(q)
// sélection de u t.q. la distance dans q est min
u = min(q, distance)
si u == t // on a atteint la cible
retourne distance
q = remove(q, u)
// voisin de u encore dans q
pour chaque v dans voisinage(u, q)
// on met à jour la distance du voisin en passant par u
n_distance = distance[u] + w(u, v)
si n_distance < distance[v]
distance[v] = n_distance
retourne distance
```
# Algorithme de Dijkstra
* Cet algorithme, nous donne le plus court chemin mais...
* ne nous donne pas le chemin!
## Comment modifier l'algorithme pour avoir le chemin?
. . .
* Pour chaque nouveau noeud à visiter, il suffit d'enregistrer d'où on est venu!
* On a besoin d'un tableau `precedent`.
## Modifier le pseudo-code ci-dessus pour ce faire (3min matrix)
# Algorithme de Dijkstra
\footnotesize
```C
tab, tab dijkstra(graph, s, t)
pour chaque v dans graphe
distance[v] = infini
precedent[v] = indéfini
q = ajouter(q, v)
distance[s] = 0
tant que non_vide(q)
// sélection de u t.q. la distance dans q est min
u = min(q, distance)
si u == t
retourne distance
q = remove(q, u)
// voisin de u encore dans q
pour chaque v dans voisinage(u, q)
n_distance = distance[u] + w(u, v)
si n_distance < distance[v]
distance[v] = n_distance
precedent[v] = u
retourne distance, precedent
```
# Algorithme de Dijkstra
## Comment reconstruire un chemin ?
. . .
```C
pile parcours(precedent, s, t)
sommets = vide
u = t
// on a atteint t ou on ne connait pas de chemin
si u != s && precedent[u] != indéfini
tant que vrai
sommets = empiler(sommets, u)
u = precedent[u]
si u == s // la source est atteinte
retourne sommets
retourne sommets
```
# Algorithme de Dijkstra amélioré
## On peut améliorer l'algorithme
* Avec une file de priorité!
## Une file de priorité est
* Une file dont chaque élément possède une priorité,
* Elle existe en deux saveurs: `min` ou `max`:
* File `min`: les éléments les plus petits sont retirés en premier.
* File `max`: les éléments les plus grands sont retirés en premier.
* On regarde l'implémentation de la `max`.
## Comment on fait ça?
. . .
* On insère les éléments à haute priorité tout devant dans la file!
# Les files de priorité
## Trois fonction principales
```C
booléen est_vide(element) // triviale
element enfiler(element, data, priorite)
data defiler(element)
rien changer_priorite(element, data, priorite)
nombre priorite(element) // utilitaire
```
## Pseudo-implémentation: structure (1min)
. . .
```C
struct element
data
priorite
element suivant
```
# Les files de priorité
## Pseudo-implémentation: enfiler (2min)
. . .
```C
element enfiler(element, data, priorite)
n_element = creer_element(data, priorite)
si est_vide(element)
retourne n_element
si priorite(n_element) > priorite(element)
n_element.suivant = element
retourne n_element
sinon
tmp = element
prec = element
tant que !est_vide(tmp) && priorite < priorite(tmp)
prec = tmp
tmp = tmp.suivant
prev.suivant = n_element
n_element.suivant = tmp
retourne element
```
# Les files de priorité
## Pseudo-implémentation: defiler (2min)
. . .
```C
data, element defiler(element)
si est_vide(element)
retourne AARGL!
sinon
tmp = element.data
n_element = element.suivant
liberer(element)
retourne tmp, n_element
```
# Algorithme de Dijkstra avec file de priorité min
```C
distance, precedent dijkstra(graphe, s, t):
distance[source] = 0
fp = file_p_vide()
pour v dans sommets(graphe)
si v != s
distance[v] = infini
precedent[v] = indéfini
fp = enfiler(fp, v, distance[v])
tant que !est_vide(fp)
u, fp = defiler(fp)
pour v dans voisinage de u
n_distance = distance[u] + w(u, v)
si n_distance < distance[v]
distance[v] = n_distance
precedent[v] = u
fp = changer_priorite(fp, v, n_distance)
retourne distance, precedent
```
# Algorithme de Dijkstra avec file
\footnotesize
```C
distance dijkstra(graphe, s, t)
---------------------------------------------------------
pour v dans sommets(graphe)
O(V) si v != s
distance[v] = infini
O(V) fp = enfiler(fp, v, distance[v]) // notre impl est nulle
------------------O(V * V)-------------------------------
tant que !est_vide(fp)
O(1) u, fp = defiler(fp)
---------------------------------------------------------
O(E) pour v dans voisinage de u
n_distance = distance[u] + w(u, v)
si n_distance < distance[v]
distance[v] = n_distance
O(V) fp = changer_priorite(fp, v, n_distance)
---------------------------------------------------------
retourne distance
```
* Total: $\mathcal{O}(|V|^2+|E|\cdot |V|)$:
* Graphe dense: $\mathcal{O}(|V|^3)$
* Graphe peu dense: $\mathcal{O}(|V|^2)$
# Algorithme de Dijkstra avec file
## On peut faire mieux
* Avec une meilleure implémentation de la file de priorité:
* Tas binaire: $\mathcal{O}(|V|\log|V|+|E|\log|V|)$.
* Tas de Fibonnacci: $\mathcal{O}(|V|+|E|\log|V|)$
* Graphe dense: $\mathcal{O}(|V|^2\log|V|)$.
* Graphe peu dense: $\mathcal{O}(|V|\log|V|)$.
# Algorithme de Dijkstra (exercice, 5min)
![L'exercice.](figs/dijkstra_exo.png){width=60%}
* Donner la liste de priorité, puis...
## A chaque étape donner:
* Le tableau des distances à `a`;
* Le tableau des prédécesseurs;
* L'état de la file de priorité.
# Algorithme de Dijkstra (corrigé)
![Le corrigé partie 1.](figs/dijkstra_ex_0.png)
# Algorithme de Dijkstra (corrigé)
![Le corrigé partie 2.](figs/dijkstra_ex_1.png)
# Algorithme de Dijkstra (corrigé)
![Le corrigé partie 3.](figs/dijkstra_ex_2.png)
# Algorithme de Dijkstra (corrigé)
![Le corrigé partie 4.](figs/dijkstra_ex_3.png)
# Algorithme de Dijkstra (corrigé)
![Le corrigé partie 5.](figs/dijkstra_ex_4.png)
# Algorithme de Dijkstra (corrigé)
![Le corrigé partie 6.](figs/dijkstra_ex_5.png)
# Limitation de l'algorithme de Dijkstra
## Que se passe-t-il pour?
![Exemple.](figs/exemple_neg.png){width=50%}
## Quel est le problème?
. . .
* L'algorithme n'essaiera jamais le chemin `s->x->y->v` et prendra direct `s->v`.
* Ce problème n'apparaît que s'il y a des poids négatifs.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment