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))