ioCode

Algorithme de Kruskal

Arbres recouvrants • Exercices 2A

L'algorithme de Kruskal permet de trouver l'arbre recouvrant de poids minimum dans un graphe connexe non orienté et pondéré. Cet exercice vous guide dans l'implémentation de la structure de données Unir-Trouver ou Union-Find nécessaire pour détecter les cycles efficacement, puis dans l'écriture de l'algorithme de Kruskal sous deux formes différentes.

On définit les types algébriques suivants pour modélier un sommet, un graphe, une arête et une liste d'arêtes (qui pourrait être un arbre).

type sommet = int
type arete = { u : sommet; v : sommet; poids : int }
type graphe = (sommet * int) list array
type arbre = arete list
type union_find = { parent : int array; rang : int array }

Le module FilePriorite ne sera utilisé qu'à la dernière question.

  1. Initialiser l'Union-Find : écrire une fonction initialiser_uf : int -> union_find qui crée et renvoie une structure Union-Find pour n éléments. Chaque élément est initialement son propre parent et son rang est 0. Exemple d'utilisation : let uf = initialiser_uf 3 in (uf.parent.(0), uf.rang.(0)) renvoie (0,0).
  2. Trouver avec compression de chemin : écrire une fonction récursive trouver_uf : union_find -> int -> int qui renvoie le représentant de l'ensemble contenant x, tout en effectuant la compression de chemin pour aplatir l'arbre.
  3. Unir par rang : écrire une fonction unir_uf : union_find -> int -> int -> unit qui fusionne les ensembles contenant x et y. L'arbre avec le rang le plus faible doit être attaché à la racine de l'autre. Si les rangs sont égaux, on choisit arbitrairement une racine et on incrémente son rang.
  4. Lister les arêtes : écrire une fonction lister_aretes : (int * int) list list -> (int * int * int) list qui transforme le graphe en une liste de triplets (source, destination, poids). Pour ne pas avoir de doublons, on ne gardera que les arêtes où source < destination. Exemple d'utilisation : let g = [[(1, 10)]; [(0, 10)]] in lister_aretes g renvoie [(0, 1, 10)].
  5. Prim (version tri) : écrire une fonction kruskal_tri_liste : (int * int) list list -> (int * int * int) list qui implémente l'algorithme de Kruskal en triant préalablement la liste complète des arêtes par ordre croissant de poids. Exemple d'utilisation : let g = [[(1, 10); (2, 5)]; [(0, 10); (2, 1)]; [(0, 5); (1, 1)]] in prim_tri_liste g renvoie l'arbre couvrant formé des arêtes de poids 1 et 5.
  6. Prim (version file de priorité) : écrire une fonction kruskal_file : (int * int) list list -> (int * int * int) list qui implémente Kruskal en utilisant le module FilePriorite fourni, pour extraire au fur et à mesure l'arête de poids le plus faible au lieu de trier toute la liste d'un coup. Exemple d'utilisation : let g = [[(1, 10); (2, 5)]; [(0, 10); (2, 1)]; [(0, 5); (1, 1)]] in prim_file g renvoie un résultat équivalent à la question précédente.
Unir-Trouver - AVANT : FIND(5) APRÈS : COMPRESSION DE CHEMIN 1 8 2 3 4 5 1 8 2 3 4 5 AVANT : UNION(5, 7) APRÈS : UNION PAR RANG 1 Rang=2 2 3 5 4 Rang=1 7 Rang(1) > Rang(4) → 4 devient fils de 1 1 Rang=2 2 3 5 4 7
Langage
Console initialisée. En attente de l'interpréteur...