diff --git a/Maths/tp/Graphs/2_tp/TP2-ArbresCouvrants.pdf b/Maths/tp/Graphs/2_tp/TP2-ArbresCouvrants.pdf new file mode 100644 index 0000000..25651fb Binary files /dev/null and b/Maths/tp/Graphs/2_tp/TP2-ArbresCouvrants.pdf differ diff --git a/Maths/tp/Graphs/2_tp/intro.py b/Maths/tp/Graphs/2_tp/intro.py new file mode 100644 index 0000000..ad3b393 --- /dev/null +++ b/Maths/tp/Graphs/2_tp/intro.py @@ -0,0 +1,249 @@ +import networkx as nx +import matplotlib.pyplot as plt + +import random #pour des nombres al ́eatoires + + + +G1 = nx.Graph() +G1.add_edge(0,1,weight=5) +G1.add_edge(0,2,weight=3) +G1.add_edge(0,3,weight=3) +G1.add_edge(0,4,weight=1) +G1.add_edge(1,2,weight=2) +G1.add_edge(2,3,weight=4) +G1.add_edge(3,4,weight=3) +G1.add_edge(3,5,weight=2) +G1.add_edge(4,5,weight=1) +dico_positions = {0:(0,0),1:(2,-1),2:(1.8,-3),3:(-0.3,-2),4:(-2,-1),5:(-2.5,-3)} +nx.draw(G1,dico_positions,with_labels=True) +2 +nx.draw_networkx_edge_labels(G1,dico_positions, +edge_labels=nx.get_edge_attributes(G1,"weight")) +plt.show() + + + +G2 = nx.Graph() +G2.add_edge("A", "B", weight=7) +G2.add_edge("A", "C", weight=8) +G2.add_edge("A", "J", weight=6) +G2.add_edge("B", "E", weight=4) +G2.add_edge("C", "I", weight=9) +G2.add_edge("C", "D", weight=5) +G2.add_edge("D", "E", weight=3) +G2.add_edge("D", "F", weight=5) +G2.add_edge("D", "G", weight=16) +G2.add_edge("E", "J", weight=3) +G2.add_edge("E", "K", weight=2) +G2.add_edge("F", "G", weight=8) +G2.add_edge("F", "H", weight=4) +G2.add_edge("G", "H", weight=12) +G2.add_edge("G", "J", weight=1) +G2.add_edge("G", "L", weight=12) +G2.add_edge("I", "J", weight=6) +G2.add_edge("K", "L", weight=10) +dico_positions2 = {"A":(0,0),"C":(2,0),"D":(4,0),"F":(6,0),"B":(1,-2),"E":(3,-2),"G":(5,-2),"H":(7,-2), "I":(1,-4), "J":(3,-4), "K":(5,-4), "L":(7,-4)} +nx.draw(G2, with_labels=True, pos=dico_positions2) +nx.draw_networkx_edge_labels(G2,dico_positions2, +edge_labels=nx.get_edge_attributes(G2,"weight")) +plt.show() + + + +def aretes_traversantes(G, S): + """ Renvoie la liste des arêtes traversantes de G pour S + Entrées : + G : un graphe + S : une liste de sommets + Sortie : + L : la liste des arêtes traversantes de G pour S + """ + L = [] + for i in S: + for j in G.edges(i): + if j not in S: + L.append(i,j) + return L + +# Impl ́ementer une version simplifi ́ee de l’algorithme de Prim qui ne se soucie pas des +# poids des arˆetes, avec une fonction algo prim simple(G) qui calcule un arbre couvrant +# de G (pas forc ́ement de poids minimal). Pour cela, `a chaque ́etape, l’algorithme prendra +# une arˆete quelconque parmi les arˆetes autoris ́ees et l’ajoutera `a l’arbre calcul ́e jusqu’`a +# pr ́esent. + +# La fonction renverra la liste des arˆetes de l’arbre couvrant. Tester avec les graphes G1 +# ou G2 des Figures 1 et 2, puis ́eventuellement avec des graphes al ́eatoires. +# Conseil : maintenir une liste sommets visites des sommets visit ́es et une liste des +# arˆetes s ́electionn ́ees. `A chaque ́etape il faudra consid ́erer toutes les arˆetes entre les som- +# mets visit ́es et les sommets non-visit ́es grˆace `a aretes traversantes(G,sommets visites). + +def algo_prim_simple(G): + """ Renvoie la liste des arêtes de l'arbre couvrant de G + Entrée : + G : un graphe + Sortie : + L : la liste des arêtes de l'arbre couvrant de G + """ + L = [] + sommets_visites = [] + sommets_non_visites = list(G.nodes()) + sommets_visites.append(sommets_non_visites[0]) + sommets_non_visites.remove(sommets_non_visites[0]) + while len(sommets_visites) != len(G.nodes()): + for i in sommets_visites: + for j in G.edges(i): + if j[1] not in sommets_visites: + L.append(j) + sommets_visites.append(j[1]) + sommets_non_visites.remove(j[1]) + break + return L, sum([G.get_edge_data(i[0],i[1])["weight"] for i in L]) + + +# Impl ́ementer l’algorithme de Prim au complet, par une fonction algo prim(G) qui +# renvoie la liste des arˆetes de l’arbre couvrant de poids minimal de G calcul ́e par l’algo- +# rithme. Tester. +# Algorithme de Prim : +# • Initialiser T avec +# { +# sommets : un sommet de G qu’on choisit +# arˆetes : aucune +# • R ́ep ́eter tant que T ne couvre pas tous les sommets : +# ⋆ Trouver toutes les arˆetes de G qui relient un sommet de T et un +# sommet ext ́erieur `a T +# ⋆ Parmi celles-ci, choisir une arˆete de poids le plus petit possible +# ⋆ Ajouter `a T cette arˆete et le sommet correspondant +# • S’arrˆeter d`es que tous les sommets de G sont dans T +# • Retourner T + +def algo_prim(G): + """ Renvoie la liste des arêtes de l'arbre couvrant de poids minimal de G + Entrée : + G : un graphe + Sortie : + L : la liste des arêtes de l'arbre couvrant de poids minimal de G + """ + L = [] + sommets_visites = [] + sommets_non_visites = list(G.nodes()) + sommets_visites.append(sommets_non_visites[0]) + sommets_non_visites.remove(sommets_non_visites[0]) + while len(sommets_visites) != len(G.nodes()): + arretes_traversantes = [] + for i in sommets_visites: + for j in G.edges(i): + if j[1] not in sommets_visites: + arretes_traversantes.append(j) + arrete_min = arretes_traversantes[0] + for i in arretes_traversantes: + if G.get_edge_data(i[0],i[1])["weight"] < G.get_edge_data(arrete_min[0],arrete_min[1])["weight"]: + arrete_min = i + L.append(arrete_min) + sommets_visites.append(arrete_min[1]) + sommets_non_visites.remove(arrete_min[1]) + # Return L et le poids total + return L, sum([G.get_edge_data(i[0],i[1])["weight"] for i in L]) + +# teste moi les algo precedents +print(algo_prim_simple(G1)) +print(algo_prim(G1)) +print(algo_prim_simple(G2)) +print(algo_prim(G2)) + + +# Exo 2 : Algorithme de Kruskal + +# Impl ́ementer l’algorithme de Kruskal, par une fonction algo kruskal(G) qui renvoie +# la liste des arˆetes de l’arbre couvrant de poids minimal de G calcul ́e par l’algorithme. +# Tester. +# Algorithme de Kruskal : +# • Initialiser T avec +# { +# sommets : tous les sommets de G +# arˆetes : aucune +# • Tant que T n’est pas un arbre couvrant : +# ⋆ Trouver une arˆete de poids minimal qui relie deux sommets de T +# ⋆ Ajouter `a T cette arˆete +# ⋆ Supprimer les arˆetes de T qui forment un cycle +# • S’arrˆeter d`es que T est un arbre couvrant +# • Retourner T + +def algo_kruskal(G): + """ Renvoie la liste des arêtes de l'arbre couvrant de poids minimal de G + Entrée : + G : un graphe + Sortie : + L : la liste des arêtes de l'arbre couvrant de poids minimal de G + """ + L = [] + sommets_visites = [] + sommets_non_visites = list(G.nodes()) + sommets_visites.append(sommets_non_visites[0]) + sommets_non_visites.remove(sommets_non_visites[0]) + while len(sommets_visites) != len(G.nodes()): + arretes_traversantes = [] + for i in sommets_visites: + for j in G.edges(i): + if j[1] not in sommets_visites: + arretes_traversantes.append(j) + arrete_min = arretes_traversantes[0] + for i in arretes_traversantes: + if G.get_edge_data(i[0],i[1])["weight"] < G.get_edge_data(arrete_min[0],arrete_min[1])["weight"]: + arrete_min = i + L.append(arrete_min) + sommets_visites.append(arrete_min[1]) + sommets_non_visites.remove(arrete_min[1]) + return L, sum([G.get_edge_data(i[0],i[1])["weight"] for i in L]) + +print(algo_kruskal(G1)) +print(algo_kruskal(G2)) + + +# Il existe un autre algorithme d’arbre couvrant de poids minimal, l’algorithme de Bor ̊uvka. Le +# comprendre et l’impl ́ementer. + +# Algorithme de Bor ̊uvka : +# F ← vide +# Tant que G n'est pas réduit à un sommet faire +# Détruire les boucles de G (*) +# Remplacer les arêtes multiples entre deux sommets par une seule dont le poids est le minimum +# Pour tout x, sommet de G, faire +# Trouver l'arête e_x de poids minimum adjacente à x +# F ← F union e_x +# Contracter e_x (**) +# fin pour +# fin tant que +# renvoyer F + +def algo_boruvka(G): + """ Renvoie la liste des arêtes de l'arbre couvrant de poids minimal de G + Entrée : + G : un graphe + Sortie : + L : la liste des arêtes de l'arbre couvrant de poids minimal de G + """ + L = [] + while len(G.nodes()) != 1: + # (*) Détruire les boucles de G + for i in G.edges(): + if i[0] == i[1]: + G.remove_edge(i[0],i[1]) + # Remplacer les arêtes multiples entre deux sommets par une seule dont le poids est le minimum + for i in G.edges(): + if len(G.edges(i[0],i[1])) > 1: + min = G.get_edge_data(i[0],i[1])["weight"] + for j in G.edges(i[0],i[1]): + if G.get_edge_data(j[0],j[1])["weight"] < min: + min = G.get_edge_data(j[0],j[1])["weight"] + for j in G.edges(i[0],i[1]): + if G.get_edge_data(j[0],j[1])["weight"] != min: + G.remove_edge(j[0],j[1]) + # Pour tout x, sommet de G, faire + for i in G.nodes(): + # Trouver l'arête e_x de poids minimum adjacente à x + min = 10000 + return L, sum([G.get_edge_data(i[0],i[1])["weight"] for i in L]) + +print(algo_boruvka(G1)) +print(algo_boruvka(G2)) \ No newline at end of file