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.
- Initialiser l'Union-Find : écrire une fonction1IndiceUtilise Array.init pour initialiser le tableau des parents et Array.make pour celui des rangs.
initialiser_uf : int -> union_findqui crée et renvoie une structure Union-Find pourné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). - Trouver avec compression de chemin : écrire une fonction récursive2IndicePense à la compression de chemin en mettant à jour le parent de 'x' avec le résultat de l'appel récursif.
trouver_uf : union_find -> int -> intqui renvoie le représentant de l'ensemble contenantx, tout en effectuant la compression de chemin pour aplatir l'arbre. - Unir par rang : écrire une fonction3IndiceCompare les rangs des racines. Attache l'arbre le moins profond sous l'arbre le plus profond.
unir_uf : union_find -> int -> int -> unitqui fusionne les ensembles contenantxety. 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. - Lister les arêtes : écrire une fonction4IndiceParcours la liste d'adjacence en mémorisant l'indice du sommet courant. Pour éviter les doublons (graphe non orienté), ne conserve que les arêtes (u, v, w) où u < v.
lister_aretes : (int * int) list list -> (int * int * int) listqui 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 grenvoie[(0, 1, 10)]. - Prim (version tri) : écrire une fonction5IndiceUtilise List.sort pour trier toutes les arêtes, puis parcours cette liste en utilisant tes fonctions trouver_uf et unir_uf.
kruskal_tri_liste : (int * int) list list -> (int * int * int) listqui 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 grenvoie l'arbre couvrant formé des arêtes de poids 1 et 5. - Prim (version file de priorité) : écrire une fonction6IndiceInsère d'abord toutes les arêtes dans la file. Extraits le minimum itérativement tant que l'arbre n'a pas n-1 arêtes et que la file n'est pas vide.
kruskal_file : (int * int) list list -> (int * int * int) listqui implémente Kruskal en utilisant le moduleFilePrioritefourni, 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 grenvoie un résultat équivalent à la question précédente.
Langage
Console initialisée. En attente de l'interpréteur...