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