11. Graphe

graph LR;
1-->2 & 3 & 5 & 8;
2-->9;
3-->5;
4-->3;
5-->6 & 7 & 8;
6-->4 & 7;
7-->6 & 7;
8-->1 & 7 & 9;
9-->7 & 9;

En mémoire, on peut représenter un graphe par une matrice d’adjacence :

\nearrow 1 2 3 4 5 6 7 8 9
1 0 1 1 0 1 0 0 1 0
2 0 0 0 0 0 0 0 0 1
3 0 0 0 0 1 0 0 0 0
4 0 0 1 0 0 0 0 0 0
5 0 0 0 0 0 1 1 1 0
6 0 0 0 1 0 0 1 0 0
7 0 0 0 0 0 1 1 0 0
8 1 0 0 0 0 0 1 0 1
9 0 0 0 0 0 0 1 0 1

En C :

#define MAX 100
typedef struct gra {
    int graphe[MAX][MAX];
    int nbSommets;
} Graphe;

On peut représenter en mémoire un graphe par des listes d’adjacences :
1: 2, 3, 5, 8
2: 9
3: 5
Utile lorsque le nombre d’arcs du graphe est \ll n^2 (n le nombre de sommets).

Remarques

Le schéma précédent illustre un graphe orienté (arc avec un sens). On rencontre aussi des graphes non-orientés (arrêtes).

Vocabulaire

Chemin dans un graphe : Longueur d’un chemin.
Circuit : Dans le graphe ci-dessous, 2 et 3 forment un circuit (je crois?).

graph LR
1-->2
2-->3
3-->2 & 5

Parcours en profondeur dans un Graphe

graph LR;
1-->2 & 7;
2-->9;
3-->1 & 5;
4-->3;
5-->6 & 7;
6-->4 & 7;
7-->8;
8-->1 & 7 & 9;
9-->7 & 9;
// On suppose la structure en C précédente

void estAccessible(Graphe * g, int s, int * tab);

/*
`sd` Sommet de Départ et `sa` Sommet d'Arrivé
On prend *g et pas g pour éviter de recopié le graphe (car il est grand)
donc on prend son adresse.
*/
int chemin(Graphe * g, int sd, int sa) {
    int T[g->nbSommets]; // indique les sommets visités
    for(int i = 0; i < g->nbSommets; i++)
        T[i] = 0;
    estAccessible(g, sd, T);

    return T[sa];
}

/*
`tab` est un tableau contenant au départ que des cases vides à 0
et la fonction met à 1 les cases dont les indices sont les sommets
accessibles par un chemin partant du sommet `s`.
*/
void estAccessible(Graphe * g, int s, int * tab) {
    if(tab[s] == 1) // Si `tab[s]` à déjà été visité
        return;
    tab[s] = 1;
    // Ensuite on parcours tout les successeurs possibles
    for(int i = 0; i < g->nbSommets; i++)
        if(g->graphe[s][i] == 1)
            return estAccessible(g, i, tab); // on continue le parcours à partir de `i`
}

Remarque

On pourrait améliorer la fonction en la quittant lorsque le sommet d’arrivé sa est atteint.

Trouver les circuits

graph TD
A[ ]-->B & C;
B[ ]-->D & E;
C[ ]-->E;
D[ ]-->F;
E[ ]-->D & F;
F[ ]
graph TD
A[ ]-->B & C;
B[ ]-->C & D;
C[ ]-->E;
D[ ]-->C & F;
E[ ]-->D & F;
F[ ]

Définition de pré-visite, post-visité et revisité

Lors d’un parcours en profondeur, chaque sommet peut-être soit :

Graphe (étiqueté)

Un graphe étiqueté est un graphe où chaque arc possède une étiquette (un nombre, une lettre…)

Vocabulaire (longueur d’un chemin d’un graphe étiqueté)

Par convention, la longueur d’un chemin dans un graphe étiqueté par des nombres est la somme des étiquettes des arcs empruntés par le chemin. La longueur du chemin vide est nulle.

Exemple

graph LR
1==2==>2
1--1-->3
2==3==>4
3--6-->2
4==2==>5

La longueur de 1, 2\rightarrow 2, 2, 2\rightarrow4, 4, 4\rightarrow5, 4, 4\rightarrow5, 5 est 2+3+2=7

Définition (plus court chemin et distance)

Soit un graphe étiqueté par des nombres et deux sommets d et a du graphe.
S’il existe un chemin allant de d à a qui possède la plus petite longueur parmis les chemins allant de d à a alors ce chemin est appelé le plus “court” chemin allant de d à a et sa longueur est appelée la distance de d à a.

Exemple

graph LR
1==1==>2
1--9-->3
2==1==>3

Ici la distance de 1 à 3 vaut 2 et le plus court chemin est 1, 2, 3

Contre-Exemple

graph LR
1--1-->2
1-- -1 -->1
graph TD
3
4

Dans ces 2 cas il n’y a pas de plus court chemin.
On pourrait dire que :

Problème algorithmique

Entrée: graphe `g`, `d`, `a` deux sommets de `g`
Sortie: plus court chemin (s'il existe) allant de `d` vers `a`
Illustration

illustration algorithme

Propriété

Soit un graphe G étiqueté par des nombres positifs ou nuls et d’un sommet
Si pour un sommet a on appelle C_a le plus court chemin allant de d vers a, alors :
C_{a} = C_{p} \circ p\rightarrow a
avec p une puissance de a et C_p le plus court chemin allant de d vers p
b(C_{p)} + l(p\rightarrow a) = \min(l(C_{s)} + l(s\rightarrow a),\ t_{q})\ \text{$s$ prédésseur de $a$}
avec l(C_{p}) longueur du chemin C_{p} et l(p\rightarrow a) étiquette de l’arc allant de p\rightarrow a. Si de plus d = a il faut prendre en compte le chemin vide.

Dorénavant les étiquettes seront positives ou nulles.

Algorithme de Dijkstra

Entrée: graphe `g` étiquetté, `d` sommet
Sortie: Pour chaque sommet accessible à partir de `d` : le plus court chemin allant de `d` à `i` et la distance de `d` à `i`
Illustration

illustration algorithme dijkstra

Comment traité un sommet pas encore traité ?

Exemple

exemple algorithme