ajout de tous les cours et TP préparés cet été
This commit is contained in:
245
Routage/CORRIGE.md
Normal file
245
Routage/CORRIGE.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# Corrigé des exercices — Routage
|
||||
|
||||
---
|
||||
|
||||
## Exercice 1 : Tables de routage
|
||||
|
||||
Soit le réseau suivant :
|
||||
|
||||
```
|
||||
A ---1--- B ---2--- E
|
||||
| |
|
||||
3 5
|
||||
| |
|
||||
C ---4--- D ---1--- F
|
||||
\ /
|
||||
2 1
|
||||
\ /
|
||||
G
|
||||
```
|
||||
|
||||
### Question 1 : Compléter la table de routage du routeur A
|
||||
|
||||
| Destination | Passerelle | Distance (sauts) |
|
||||
|-------------|------------|------------------|
|
||||
| B | B | 1 |
|
||||
| C | C | 1 |
|
||||
| D | C | 2 |
|
||||
| E | B | 2 |
|
||||
| F | C | 3 |
|
||||
| G | C | 2 |
|
||||
|
||||
**Explication** : Depuis A, pour atteindre :
|
||||
- B : directement connecté (1 saut)
|
||||
- C : directement connecté (1 saut)
|
||||
- D : via C (A→C→D = 2 sauts)
|
||||
- E : via B (A→B→E = 2 sauts)
|
||||
- F : via C puis D (A→C→D→F = 3 sauts)
|
||||
- G : via C (A→C→G = 2 sauts)
|
||||
|
||||
### Question 2 : Compléter la table de routage du routeur D
|
||||
|
||||
| Destination | Passerelle | Distance (sauts) |
|
||||
|-------------|------------|------------------|
|
||||
| A | C | 2 |
|
||||
| B | B | 1 |
|
||||
| C | C | 1 |
|
||||
| E | B | 2 |
|
||||
| F | F | 1 |
|
||||
| G | G | 1 |
|
||||
|
||||
---
|
||||
|
||||
## Exercice 2 : Protocole RIP
|
||||
|
||||
### Question 1 : Principe de mise à jour
|
||||
|
||||
Un routeur R reçoit de son voisin V la table suivante :
|
||||
|
||||
| Destination | Distance |
|
||||
|-------------|----------|
|
||||
| X | 2 |
|
||||
| Y | 4 |
|
||||
| Z | 1 |
|
||||
|
||||
Si R est à distance 1 de V, quelle sera la mise à jour de la table de R ?
|
||||
|
||||
**Réponse** :
|
||||
|
||||
R ajoute 1 (la distance vers V) à chaque entrée :
|
||||
|
||||
| Destination | Distance via V |
|
||||
|-------------|----------------|
|
||||
| X | 2 + 1 = 3 |
|
||||
| Y | 4 + 1 = 5 |
|
||||
| Z | 1 + 1 = 2 |
|
||||
|
||||
R ne mettra à jour sa table que si ces distances sont **inférieures** aux distances actuellement connues.
|
||||
|
||||
### Question 2 : Limite de RIP
|
||||
|
||||
Pourquoi RIP est-il limité à 15 sauts maximum ?
|
||||
|
||||
**Réponse** :
|
||||
- Au-delà de 15 sauts, la destination est considérée comme inaccessible (distance = 16 = infini)
|
||||
- Cette limite évite les boucles infinies de routage
|
||||
- Elle limite aussi la taille des réseaux pouvant utiliser RIP
|
||||
- C'est pourquoi RIP est adapté aux petits réseaux seulement
|
||||
|
||||
### Question 3 : Convergence
|
||||
|
||||
Combien de temps faut-il au minimum pour qu'une information de routage traverse 5 routeurs avec RIP ?
|
||||
|
||||
**Réponse** :
|
||||
- RIP envoie des mises à jour toutes les 30 secondes
|
||||
- Pour traverser 5 routeurs : 5 × 30 = **150 secondes** (2 min 30 s) minimum
|
||||
|
||||
---
|
||||
|
||||
## Exercice 3 : Algorithme de Dijkstra
|
||||
|
||||
### Question 1 : Exécution manuelle
|
||||
|
||||
Soit le graphe pondéré suivant :
|
||||
|
||||
```
|
||||
4
|
||||
A -----> B
|
||||
| |
|
||||
2| |1
|
||||
v v
|
||||
C -----> D -----> E
|
||||
1 3
|
||||
```
|
||||
|
||||
Appliquer l'algorithme de Dijkstra depuis A.
|
||||
|
||||
**Résolution pas à pas** :
|
||||
|
||||
| Étape | Sommet traité | d(A) | d(B) | d(C) | d(D) | d(E) |
|
||||
|-------|---------------|------|------|------|------|------|
|
||||
| Init | - | 0 | ∞ | ∞ | ∞ | ∞ |
|
||||
| 1 | A | 0 | 4 | 2 | ∞ | ∞ |
|
||||
| 2 | C | 0 | 4 | 2 | 3 | ∞ |
|
||||
| 3 | D | 0 | 4 | 2 | 3 | 6 |
|
||||
| 4 | B | 0 | 4 | 2 | 3 | 6 |
|
||||
| 5 | E | 0 | 4 | 2 | 3 | 6 |
|
||||
|
||||
**Résultat final** :
|
||||
- A → A : 0
|
||||
- A → B : 4 (chemin direct)
|
||||
- A → C : 2 (chemin direct)
|
||||
- A → D : 3 (via C)
|
||||
- A → E : 6 (via C puis D)
|
||||
|
||||
### Question 2 : Reconstruction du chemin
|
||||
|
||||
Quel est le plus court chemin de A vers E ?
|
||||
|
||||
**Réponse** : A → C → D → E (coût total : 6)
|
||||
|
||||
---
|
||||
|
||||
## Exercice 4 : Protocole OSPF
|
||||
|
||||
### Question 1 : Calcul du coût d'une liaison
|
||||
|
||||
La formule OSPF est : `coût = 10^8 / débit`
|
||||
|
||||
Calculer le coût des liaisons suivantes :
|
||||
|
||||
| Type de liaison | Débit | Coût |
|
||||
|-----------------|-------|------|
|
||||
| Ethernet 10 Mbps | 10 × 10^6 bps | 10^8 / 10^7 = **10** |
|
||||
| Fast Ethernet 100 Mbps | 100 × 10^6 bps | 10^8 / 10^8 = **1** |
|
||||
| Gigabit Ethernet | 10^9 bps | 10^8 / 10^9 = **0.1 ≈ 1** |
|
||||
| Liaison série 2 Mbps | 2 × 10^6 bps | 10^8 / (2×10^6) = **50** |
|
||||
|
||||
**Note** : En pratique, le coût minimum est souvent fixé à 1.
|
||||
|
||||
### Question 2 : Choix du meilleur chemin
|
||||
|
||||
Soit un réseau avec deux chemins possibles de A vers Z :
|
||||
- Chemin 1 : A → B → Z avec liaisons à 100 Mbps et 10 Mbps
|
||||
- Chemin 2 : A → C → D → Z avec trois liaisons à 100 Mbps
|
||||
|
||||
Quel chemin OSPF choisira-t-il ?
|
||||
|
||||
**Calcul** :
|
||||
- Chemin 1 : coût = 1 + 10 = **11**
|
||||
- Chemin 2 : coût = 1 + 1 + 1 = **3**
|
||||
|
||||
**Réponse** : OSPF choisira le **chemin 2** car son coût (3) est inférieur à celui du chemin 1 (11), même s'il traverse plus de routeurs.
|
||||
|
||||
---
|
||||
|
||||
## Exercice 5 : Comparaison RIP vs OSPF
|
||||
|
||||
### Question : Différences fondamentales
|
||||
|
||||
| Critère | RIP | OSPF |
|
||||
|---------|-----|------|
|
||||
| Type d'algorithme | Vecteur de distance (Bellman-Ford) | État de liens (Dijkstra) |
|
||||
| Métrique | Nombre de sauts | Coût (basé sur le débit) |
|
||||
| Vision du réseau | Locale (voisins uniquement) | Globale (carte complète) |
|
||||
| Limite | 15 sauts max | Pas de limite de sauts |
|
||||
| Convergence | Lente (30s entre mises à jour) | Rapide |
|
||||
| Complexité | Simple | Plus complexe |
|
||||
| Adapté pour | Petits réseaux | Grands réseaux |
|
||||
|
||||
---
|
||||
|
||||
## Exercice 6 : Implémentation Python de Dijkstra
|
||||
|
||||
```python
|
||||
def dijkstra(graphe, source):
|
||||
"""
|
||||
Algorithme de Dijkstra pour trouver les plus courts chemins.
|
||||
|
||||
:param graphe: dict {sommet: [(voisin, poids), ...]}
|
||||
:param source: sommet de départ
|
||||
:return: dict des distances minimales
|
||||
"""
|
||||
# Initialisation
|
||||
distances = {sommet: float('inf') for sommet in graphe}
|
||||
distances[source] = 0
|
||||
non_visites = set(graphe.keys())
|
||||
|
||||
while non_visites:
|
||||
# Sélectionner le sommet non visité avec la plus petite distance
|
||||
courant = min(non_visites, key=lambda s: distances[s])
|
||||
non_visites.remove(courant)
|
||||
|
||||
# Si la distance est infinie, les sommets restants sont inaccessibles
|
||||
if distances[courant] == float('inf'):
|
||||
break
|
||||
|
||||
# Mettre à jour les distances des voisins
|
||||
for voisin, poids in graphe[courant]:
|
||||
nouvelle_distance = distances[courant] + poids
|
||||
if nouvelle_distance < distances[voisin]:
|
||||
distances[voisin] = nouvelle_distance
|
||||
|
||||
return distances
|
||||
|
||||
|
||||
# Test
|
||||
graphe = {
|
||||
'A': [('B', 4), ('C', 2)],
|
||||
'B': [('D', 1)],
|
||||
'C': [('D', 1)],
|
||||
'D': [('E', 3)],
|
||||
'E': []
|
||||
}
|
||||
|
||||
print(dijkstra(graphe, 'A'))
|
||||
# Résultat : {'A': 0, 'B': 4, 'C': 2, 'D': 3, 'E': 6}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
415
Routage/Corrige_TP_GPS_Navigator.py
Normal file
415
Routage/Corrige_TP_GPS_Navigator.py
Normal file
@@ -0,0 +1,415 @@
|
||||
"""
|
||||
Corrigé du TP GPS Navigator — Itinéraires optimaux
|
||||
"""
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 1 : Modélisation du réseau
|
||||
# =============================================================================
|
||||
|
||||
class ReseauRoutier:
|
||||
"""Représente un réseau routier sous forme de graphe."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialise un réseau vide."""
|
||||
self.graphe = {}
|
||||
|
||||
def ajouter_ville(self, ville):
|
||||
"""
|
||||
Ajoute une ville (sommet) au réseau.
|
||||
|
||||
:param ville: (str) Nom de la ville
|
||||
"""
|
||||
if ville not in self.graphe:
|
||||
self.graphe[ville] = []
|
||||
|
||||
def ajouter_route(self, ville1, ville2, distance):
|
||||
"""
|
||||
Ajoute une route bidirectionnelle entre deux villes.
|
||||
|
||||
:param ville1: (str) Première ville
|
||||
:param ville2: (str) Deuxième ville
|
||||
:param distance: (int) Distance en km
|
||||
"""
|
||||
# S'assurer que les villes existent
|
||||
self.ajouter_ville(ville1)
|
||||
self.ajouter_ville(ville2)
|
||||
|
||||
# Ajouter la route dans les deux sens
|
||||
self.graphe[ville1].append((ville2, distance))
|
||||
self.graphe[ville2].append((ville1, distance))
|
||||
|
||||
def get_voisins(self, ville):
|
||||
"""
|
||||
Retourne la liste des voisins d'une ville avec les distances.
|
||||
|
||||
:param ville: (str) Nom de la ville
|
||||
:return: (list) Liste de tuples (voisin, distance)
|
||||
"""
|
||||
return self.graphe.get(ville, [])
|
||||
|
||||
def afficher(self):
|
||||
"""Affiche le réseau."""
|
||||
for ville, voisins in self.graphe.items():
|
||||
print(f"{ville} -> {voisins}")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 2 : Algorithme de Dijkstra
|
||||
# =============================================================================
|
||||
|
||||
def selectionner_minimum(distances, non_visites):
|
||||
"""
|
||||
Sélectionne le sommet non visité avec la distance minimale.
|
||||
|
||||
:param distances: (dict) Distances actuelles
|
||||
:param non_visites: (set) Ensemble des sommets non visités
|
||||
:return: (str) Le sommet avec la distance minimale
|
||||
"""
|
||||
minimum = None
|
||||
distance_min = float('inf')
|
||||
|
||||
for sommet in non_visites:
|
||||
if distances[sommet] < distance_min:
|
||||
distance_min = distances[sommet]
|
||||
minimum = sommet
|
||||
|
||||
return minimum
|
||||
|
||||
|
||||
def dijkstra(reseau, depart):
|
||||
"""
|
||||
Algorithme de Dijkstra pour trouver les plus courts chemins.
|
||||
|
||||
:param reseau: (ReseauRoutier) Le réseau routier
|
||||
:param depart: (str) Ville de départ
|
||||
:return: (dict) Distances minimales depuis le départ
|
||||
"""
|
||||
# Initialisation
|
||||
distances = {ville: float('inf') for ville in reseau.graphe}
|
||||
distances[depart] = 0
|
||||
non_visites = set(reseau.graphe.keys())
|
||||
|
||||
while non_visites:
|
||||
# Sélectionner le sommet avec la distance minimale
|
||||
courant = selectionner_minimum(distances, non_visites)
|
||||
|
||||
if courant is None or distances[courant] == float('inf'):
|
||||
break
|
||||
|
||||
non_visites.remove(courant)
|
||||
|
||||
# Mettre à jour les distances des voisins
|
||||
for voisin, poids in reseau.get_voisins(courant):
|
||||
nouvelle_distance = distances[courant] + poids
|
||||
if nouvelle_distance < distances[voisin]:
|
||||
distances[voisin] = nouvelle_distance
|
||||
|
||||
return distances
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 3 : Reconstruction du chemin
|
||||
# =============================================================================
|
||||
|
||||
def dijkstra_avec_chemin(reseau, depart):
|
||||
"""
|
||||
Dijkstra avec mémorisation des prédécesseurs.
|
||||
|
||||
:param reseau: (ReseauRoutier) Le réseau routier
|
||||
:param depart: (str) Ville de départ
|
||||
:return: (tuple) (distances, predecesseurs)
|
||||
"""
|
||||
distances = {ville: float('inf') for ville in reseau.graphe}
|
||||
predecesseurs = {ville: None for ville in reseau.graphe}
|
||||
distances[depart] = 0
|
||||
non_visites = set(reseau.graphe.keys())
|
||||
|
||||
while non_visites:
|
||||
courant = selectionner_minimum(distances, non_visites)
|
||||
|
||||
if courant is None or distances[courant] == float('inf'):
|
||||
break
|
||||
|
||||
non_visites.remove(courant)
|
||||
|
||||
for voisin, poids in reseau.get_voisins(courant):
|
||||
nouvelle_distance = distances[courant] + poids
|
||||
if nouvelle_distance < distances[voisin]:
|
||||
distances[voisin] = nouvelle_distance
|
||||
predecesseurs[voisin] = courant
|
||||
|
||||
return distances, predecesseurs
|
||||
|
||||
|
||||
def reconstruire_chemin(predecesseurs, depart, arrivee):
|
||||
"""
|
||||
Reconstruit le chemin du départ à l'arrivée.
|
||||
|
||||
:param predecesseurs: (dict) Dictionnaire des prédécesseurs
|
||||
:param depart: (str) Ville de départ
|
||||
:param arrivee: (str) Ville d'arrivée
|
||||
:return: (list) Chemin sous forme de liste de villes
|
||||
"""
|
||||
chemin = []
|
||||
courant = arrivee
|
||||
|
||||
while courant is not None:
|
||||
chemin.append(courant)
|
||||
courant = predecesseurs[courant]
|
||||
|
||||
chemin.reverse()
|
||||
|
||||
# Vérifier que le chemin commence bien par le départ
|
||||
if chemin[0] != depart:
|
||||
return [] # Pas de chemin trouvé
|
||||
|
||||
return chemin
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 4 : GPS Navigator
|
||||
# =============================================================================
|
||||
|
||||
class GPSNavigator:
|
||||
"""Système de navigation GPS."""
|
||||
|
||||
def __init__(self):
|
||||
self.reseau = ReseauRoutier()
|
||||
|
||||
def charger_carte(self, donnees):
|
||||
"""
|
||||
Charge une carte depuis des données.
|
||||
|
||||
:param donnees: (dict) {"villes": [...], "routes": [...]}
|
||||
"""
|
||||
for ville in donnees.get("villes", []):
|
||||
self.reseau.ajouter_ville(ville)
|
||||
|
||||
for route in donnees.get("routes", []):
|
||||
self.reseau.ajouter_route(route[0], route[1], route[2])
|
||||
|
||||
def calculer_itineraire(self, depart, arrivee):
|
||||
"""
|
||||
Calcule l'itinéraire optimal entre deux villes.
|
||||
|
||||
:param depart: (str) Ville de départ
|
||||
:param arrivee: (str) Ville d'arrivée
|
||||
:return: (dict) Informations sur l'itinéraire
|
||||
"""
|
||||
if depart not in self.reseau.graphe:
|
||||
return {"erreur": f"Ville inconnue : {depart}"}
|
||||
if arrivee not in self.reseau.graphe:
|
||||
return {"erreur": f"Ville inconnue : {arrivee}"}
|
||||
|
||||
distances, predecesseurs = dijkstra_avec_chemin(self.reseau, depart)
|
||||
|
||||
if distances[arrivee] == float('inf'):
|
||||
return {"erreur": "Aucun itinéraire trouvé"}
|
||||
|
||||
chemin = reconstruire_chemin(predecesseurs, depart, arrivee)
|
||||
|
||||
return {
|
||||
"depart": depart,
|
||||
"arrivee": arrivee,
|
||||
"distance": distances[arrivee],
|
||||
"chemin": chemin,
|
||||
"nb_etapes": len(chemin) - 1
|
||||
}
|
||||
|
||||
def afficher_itineraire(self, itineraire):
|
||||
"""Affiche l'itinéraire de manière lisible."""
|
||||
if "erreur" in itineraire:
|
||||
print(f"Erreur : {itineraire['erreur']}")
|
||||
return
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"ITINÉRAIRE : {itineraire['depart']} → {itineraire['arrivee']}")
|
||||
print(f"{'='*50}")
|
||||
print(f"Distance totale : {itineraire['distance']} km")
|
||||
print(f"Nombre d'étapes : {itineraire['nb_etapes']}")
|
||||
print(f"\nChemin :")
|
||||
for i, ville in enumerate(itineraire['chemin']):
|
||||
if i < len(itineraire['chemin']) - 1:
|
||||
print(f" {i+1}. {ville} →")
|
||||
else:
|
||||
print(f" {i+1}. {ville} (arrivée)")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
def toutes_les_distances(self, depart):
|
||||
"""
|
||||
Affiche les distances vers toutes les villes depuis un point de départ.
|
||||
|
||||
:param depart: (str) Ville de départ
|
||||
"""
|
||||
distances = dijkstra(self.reseau, depart)
|
||||
print(f"\nDistances depuis {depart} :")
|
||||
for ville, dist in sorted(distances.items(), key=lambda x: x[1]):
|
||||
if dist == float('inf'):
|
||||
print(f" {ville} : inaccessible")
|
||||
else:
|
||||
print(f" {ville} : {dist} km")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 5 : Améliorations (Bonus)
|
||||
# =============================================================================
|
||||
|
||||
class GPSNavigatorAvance(GPSNavigator):
|
||||
"""GPS avec fonctionnalités avancées."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.vitesses = {} # Vitesses moyennes par route
|
||||
|
||||
def ajouter_route_avec_vitesse(self, ville1, ville2, distance, vitesse):
|
||||
"""Ajoute une route avec sa vitesse moyenne."""
|
||||
self.reseau.ajouter_route(ville1, ville2, distance)
|
||||
cle = tuple(sorted([ville1, ville2]))
|
||||
self.vitesses[cle] = vitesse
|
||||
|
||||
def calculer_temps(self, ville1, ville2, distance):
|
||||
"""Calcule le temps de trajet en minutes."""
|
||||
cle = tuple(sorted([ville1, ville2]))
|
||||
vitesse = self.vitesses.get(cle, 50) # 50 km/h par défaut
|
||||
return (distance / vitesse) * 60 # En minutes
|
||||
|
||||
def calculer_itineraire_via(self, depart, arrivee, via):
|
||||
"""
|
||||
Calcule un itinéraire passant par des points intermédiaires.
|
||||
|
||||
:param via: (list) Liste des villes intermédiaires dans l'ordre
|
||||
"""
|
||||
etapes = [depart] + via + [arrivee]
|
||||
chemin_complet = []
|
||||
distance_totale = 0
|
||||
|
||||
for i in range(len(etapes) - 1):
|
||||
itineraire = self.calculer_itineraire(etapes[i], etapes[i + 1])
|
||||
if "erreur" in itineraire:
|
||||
return itineraire
|
||||
|
||||
if chemin_complet:
|
||||
chemin_complet.extend(itineraire['chemin'][1:])
|
||||
else:
|
||||
chemin_complet = itineraire['chemin']
|
||||
|
||||
distance_totale += itineraire['distance']
|
||||
|
||||
return {
|
||||
"depart": depart,
|
||||
"arrivee": arrivee,
|
||||
"via": via,
|
||||
"distance": distance_totale,
|
||||
"chemin": chemin_complet,
|
||||
"nb_etapes": len(chemin_complet) - 1
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 6 : Réponses aux questions
|
||||
# =============================================================================
|
||||
|
||||
"""
|
||||
RÉPONSES AUX QUESTIONS DE SYNTHÈSE
|
||||
|
||||
1. Complexité temporelle de Dijkstra :
|
||||
- Avec notre implémentation : O(V²) où V est le nombre de sommets
|
||||
- La recherche du minimum parcourt tous les sommets non visités
|
||||
- Pour chaque sommet, on parcourt ses voisins
|
||||
|
||||
2. Amélioration pour les grands graphes :
|
||||
- Utiliser un tas binaire (heap) pour la sélection du minimum : O((V+E)log V)
|
||||
- Utiliser un tas de Fibonacci : O(E + V log V)
|
||||
- Utiliser A* (A-star) qui est une variante avec heuristique
|
||||
|
||||
3. Pourquoi pas de poids négatifs :
|
||||
- Dijkstra suppose qu'une fois un sommet visité, sa distance est définitive
|
||||
- Un poids négatif pourrait permettre de trouver un chemin plus court
|
||||
en passant par un sommet déjà visité
|
||||
- Pour les poids négatifs, utiliser Bellman-Ford
|
||||
|
||||
4. Chemin passant par tous les sommets :
|
||||
- C'est le problème du voyageur de commerce (TSP)
|
||||
- Problème NP-complet, pas de solution polynomiale connue
|
||||
- On utilise des heuristiques ou des algorithmes d'approximation
|
||||
"""
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TESTS
|
||||
# =============================================================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
print("=" * 60)
|
||||
print("TEST 1 : CRÉATION DU RÉSEAU")
|
||||
print("=" * 60)
|
||||
|
||||
gps = GPSNavigator()
|
||||
|
||||
# Ajout des villes de la Côte d'Azur
|
||||
villes = ["Nice", "Monaco", "Menton", "Cannes", "Antibes", "Grasse", "Vence"]
|
||||
for ville in villes:
|
||||
gps.reseau.ajouter_ville(ville)
|
||||
|
||||
# Ajout des routes (distances en km)
|
||||
routes = [
|
||||
("Nice", "Monaco", 20),
|
||||
("Monaco", "Menton", 10),
|
||||
("Nice", "Cannes", 33),
|
||||
("Nice", "Antibes", 23),
|
||||
("Cannes", "Antibes", 11),
|
||||
("Cannes", "Grasse", 17),
|
||||
("Nice", "Grasse", 40),
|
||||
("Nice", "Vence", 22),
|
||||
("Grasse", "Vence", 15)
|
||||
]
|
||||
for v1, v2, dist in routes:
|
||||
gps.reseau.ajouter_route(v1, v2, dist)
|
||||
|
||||
print("\nRéseau routier :")
|
||||
gps.reseau.afficher()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST 2 : DIJKSTRA SIMPLE")
|
||||
print("=" * 60)
|
||||
|
||||
distances = dijkstra(gps.reseau, "Nice")
|
||||
print("\nDistances depuis Nice :")
|
||||
for ville, dist in sorted(distances.items(), key=lambda x: x[1]):
|
||||
print(f" {ville} : {dist} km")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST 3 : CALCUL D'ITINÉRAIRE")
|
||||
print("=" * 60)
|
||||
|
||||
itineraire = gps.calculer_itineraire("Menton", "Grasse")
|
||||
gps.afficher_itineraire(itineraire)
|
||||
|
||||
itineraire2 = gps.calculer_itineraire("Monaco", "Vence")
|
||||
gps.afficher_itineraire(itineraire2)
|
||||
|
||||
itineraire3 = gps.calculer_itineraire("Cannes", "Menton")
|
||||
gps.afficher_itineraire(itineraire3)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST 4 : TOUTES LES DISTANCES")
|
||||
print("=" * 60)
|
||||
|
||||
gps.toutes_les_distances("Cannes")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST 5 : ITINÉRAIRE VIA (BONUS)")
|
||||
print("=" * 60)
|
||||
|
||||
gps_avance = GPSNavigatorAvance()
|
||||
for ville in villes:
|
||||
gps_avance.reseau.ajouter_ville(ville)
|
||||
for v1, v2, dist in routes:
|
||||
gps_avance.reseau.ajouter_route(v1, v2, dist)
|
||||
|
||||
itineraire_via = gps_avance.calculer_itineraire_via("Menton", "Cannes", via=["Nice"])
|
||||
print(f"\nItinéraire Menton → Nice → Cannes :")
|
||||
print(f" Distance : {itineraire_via['distance']} km")
|
||||
print(f" Chemin : {' → '.join(itineraire_via['chemin'])}")
|
||||
@@ -28,7 +28,7 @@ L’acheminement efficace des données est crucial pour garantir la rapidité, l
|
||||
|
||||
|
||||
|
||||
### Mais dis moi Jamy, qu'est ce qu'un routeur ?
|
||||
### Mais dis-moi Jamy, qu'est-ce qu'un routeur ?
|
||||
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ L’acheminement efficace des données est crucial pour garantir la rapidité, l
|
||||
|
||||
|
||||
|
||||
Un routeur est en quelque chose un hôte, un ordinateur, qui possède deux périphériques réseau, qui disposent d'une adresse IP chacun.
|
||||
Un routeur est en quelque sorte un hôte, un ordinateur, qui possède deux périphériques réseau, qui disposent d'une adresse IP chacun.
|
||||
|
||||
Lorsque des données transitent sur le réseau, chaque routeur va en recevoir, et pourra décider de les transmettre à telle ou telle machine.
|
||||
Pour ne pas se tromper et faire le bon choix, le routeur se servira de **tables de routage.**
|
||||
@@ -91,13 +91,13 @@ Comme on peut le voir, on dispose de plusieurs informations :
|
||||
|
||||
Depuis le routeur X, pour atteindre une destination, on va indiquer par quel routeur on passera, et la distance / le coût pour atteindre notre destination.
|
||||
|
||||
On parle alors de **passerelle** quand un routeur permet d'accéder à un sous-réseau différent du notre.
|
||||
On parle alors de **passerelle** quand un routeur permet d'accéder à un sous-réseau différent du nôtre.
|
||||
|
||||
|
||||
|
||||
### Les algorithmes de routage
|
||||
|
||||
Il paraît évident qu'un réseau aussi grand qu'internet ne peut pas reposer sur des tables de routages manuelles. On a donc décidé d'automatiser cette tâche à l'aide d'algorithmes.
|
||||
Il paraît évident qu'un réseau aussi grand qu'Internet ne peut pas reposer sur des tables de routage manuelles. On a donc décidé d'automatiser cette tâche à l'aide d'algorithmes.
|
||||
Ainsi, ceux-ci permettent aux routeurs de choisir le chemin optimal pour transmettre les données. On distingue deux grandes catégories :
|
||||
|
||||
- **Les algorithmes à état de liens (Link-State)** : Chaque routeur construit une carte du réseau et calcule les meilleurs chemins avec des algorithmes comme **Dijkstra**.
|
||||
@@ -108,11 +108,11 @@ Ainsi, ceux-ci permettent aux routeurs de choisir le chemin optimal pour transme
|
||||
Ici, chaque routeur va attribuer une distance la plus courte possible à chaque destination accessible.
|
||||
Cette distance sera indiquée en unité de sauts (hop), avec un saut = un routeur traversé.
|
||||
|
||||
Pour commencer, chaque routeur va écrire dans sa table les plus proches voisins, c'est à dire les routeurs accessibles à 0 de distance.
|
||||
Pour commencer, chaque routeur va écrire dans sa table les plus proches voisins, c'est-à-dire les routeurs accessibles à 1 saut de distance.
|
||||
|
||||
Puis, toutes les 30 secondes, chaque routeur va propager les informations de sa table vers ses voisins immédiats, qui mettront leur propre table à jour avec ces informations, notamment si un chemin plus court vers une destination existe !
|
||||
Puis, toutes les 30 secondes, chaque routeur va propager les informations de sa table vers ses voisins immédiats, qui mettront leur propre table à jour avec ces informations, notamment si un chemin plus court vers une destination existe !
|
||||
|
||||
Puis que l'on dispose d'un routeur comme **direction**, et d'une **distance**, on a donc un **vecteur**.
|
||||
Puisque l'on dispose d'un routeur comme **direction**, et d'une **distance**, on a donc un **vecteur**.
|
||||
|
||||
**Attention** !
|
||||
|
||||
@@ -123,11 +123,11 @@ Si un routeur (et donc un réseau) n'est plus accessible passé 3 minutes, il se
|
||||
À retenir :
|
||||
|
||||
- Distance en terme de sauts (ou hop en anglais)
|
||||
- Chaque routeur ne possède les informations que sur son voisinnage direct. On parle de ***routing by rumor*** : aucune vision globale du réseau, on fait confiance aux voisins pour savoir ce qu'il en est.
|
||||
- Au delà de 15 sauts, on considère un routeur inaccessible.
|
||||
- Chaque routeur ne possède les informations que sur son voisinage direct. On parle de ***routing by rumor*** : aucune vision globale du réseau, on fait confiance aux voisins pour savoir ce qu'il en est.
|
||||
- Au-delà de 15 sauts, on considère un routeur inaccessible.
|
||||
- Utilise l’algorithme à vecteur de distance de Bellman-Ford et est simple à configurer, mais limité en performance.
|
||||
- Convient aux petits réseaux
|
||||
- Premiere algorithme de routage de l'histoire
|
||||
- Premier algorithme de routage de l'histoire
|
||||
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ $$
|
||||
où d est le débit nominal en bits/seconde.
|
||||
|
||||
- Chaque réseau pourra être représenté sous forme de graphe.
|
||||
- On recherchera les routes les moins couteuses, et sans cycle.
|
||||
- On recherchera les routes les moins coûteuses, et sans cycle.
|
||||
- Chaque routeur devient alors la racine d'un arbre contenant les meilleurs routes.
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ Enfin, il reste un algorithme :
|
||||
|
||||
Que nous ne verrons pas cette année.
|
||||
|
||||
Merci jamy !
|
||||
Merci Jamy !
|
||||
|
||||

|
||||
|
||||
|
||||
391
Routage/TP_GPS_Navigator.md
Normal file
391
Routage/TP_GPS_Navigator.md
Normal file
@@ -0,0 +1,391 @@
|
||||
# TP : GPS Navigator — Itinéraires optimaux
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous êtes développeur chez une startup qui souhaite concurrencer Google Maps et Waze. Votre mission : implémenter le moteur de calcul d'itinéraires en utilisant l'algorithme de **Dijkstra** pour trouver les chemins les plus courts dans un réseau routier.
|
||||
|
||||
Saviez-vous que Google Maps effectue des milliards de calculs Dijkstra chaque jour ?
|
||||
|
||||
---
|
||||
|
||||
## Objectifs
|
||||
|
||||
- Modéliser un réseau routier sous forme de graphe
|
||||
- Implémenter l'algorithme de Dijkstra
|
||||
- Calculer les itinéraires optimaux (distance ou temps)
|
||||
- Reconstruire le chemin complet entre deux points
|
||||
|
||||
---
|
||||
|
||||
## Partie 1 : Modélisation du réseau
|
||||
|
||||
### 1.1. Représentation d'un graphe
|
||||
|
||||
Un réseau routier peut être modélisé par un **graphe pondéré** :
|
||||
- Les **sommets** représentent les intersections/villes
|
||||
- Les **arêtes** représentent les routes
|
||||
- Les **poids** représentent les distances ou temps de trajet
|
||||
|
||||
Nous utiliserons un dictionnaire d'adjacence :
|
||||
|
||||
```python
|
||||
# Exemple : réseau simplifié de la Côte d'Azur
|
||||
reseau = {
|
||||
"Nice": [("Monaco", 20), ("Cannes", 33), ("Grasse", 40)],
|
||||
"Monaco": [("Nice", 20), ("Menton", 10)],
|
||||
"Cannes": [("Nice", 33), ("Grasse", 17), ("Antibes", 11)],
|
||||
"Grasse": [("Nice", 40), ("Cannes", 17)],
|
||||
"Antibes": [("Cannes", 11), ("Nice", 23)],
|
||||
"Menton": [("Monaco", 10)]
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2. Création du graphe
|
||||
|
||||
Implémenter une classe `ReseauRoutier` pour gérer le graphe :
|
||||
|
||||
```python
|
||||
class ReseauRoutier:
|
||||
"""Représente un réseau routier sous forme de graphe."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialise un réseau vide."""
|
||||
self.graphe = {}
|
||||
|
||||
def ajouter_ville(self, ville):
|
||||
"""
|
||||
Ajoute une ville (sommet) au réseau.
|
||||
|
||||
:param ville: (str) Nom de la ville
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def ajouter_route(self, ville1, ville2, distance):
|
||||
"""
|
||||
Ajoute une route bidirectionnelle entre deux villes.
|
||||
|
||||
:param ville1: (str) Première ville
|
||||
:param ville2: (str) Deuxième ville
|
||||
:param distance: (int) Distance en km
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def get_voisins(self, ville):
|
||||
"""
|
||||
Retourne la liste des voisins d'une ville avec les distances.
|
||||
|
||||
:param ville: (str) Nom de la ville
|
||||
:return: (list) Liste de tuples (voisin, distance)
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def afficher(self):
|
||||
"""Affiche le réseau."""
|
||||
for ville, voisins in self.graphe.items():
|
||||
print(f"{ville} -> {voisins}")
|
||||
```
|
||||
|
||||
**Test** :
|
||||
```python
|
||||
reseau = ReseauRoutier()
|
||||
reseau.ajouter_ville("Nice")
|
||||
reseau.ajouter_ville("Monaco")
|
||||
reseau.ajouter_route("Nice", "Monaco", 20)
|
||||
reseau.afficher()
|
||||
# Nice -> [('Monaco', 20)]
|
||||
# Monaco -> [('Nice', 20)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 2 : Algorithme de Dijkstra
|
||||
|
||||
### 2.1. Principe de l'algorithme
|
||||
|
||||
L'algorithme de Dijkstra trouve le plus court chemin depuis une source vers tous les autres sommets :
|
||||
|
||||
1. Initialiser toutes les distances à l'infini, sauf la source à 0
|
||||
2. Marquer tous les sommets comme non visités
|
||||
3. Tant qu'il reste des sommets non visités :
|
||||
- Sélectionner le sommet non visité avec la plus petite distance
|
||||
- Pour chaque voisin, mettre à jour la distance si on trouve un chemin plus court
|
||||
- Marquer le sommet comme visité
|
||||
|
||||
### 2.2. Implémentation
|
||||
|
||||
```python
|
||||
def dijkstra(reseau, depart):
|
||||
"""
|
||||
Algorithme de Dijkstra pour trouver les plus courts chemins.
|
||||
|
||||
:param reseau: (ReseauRoutier) Le réseau routier
|
||||
:param depart: (str) Ville de départ
|
||||
:return: (dict) Distances minimales depuis le départ
|
||||
"""
|
||||
# Initialisation
|
||||
distances = {ville: float('inf') for ville in reseau.graphe}
|
||||
distances[depart] = 0
|
||||
non_visites = set(reseau.graphe.keys())
|
||||
|
||||
# À compléter : boucle principale de l'algorithme
|
||||
|
||||
return distances
|
||||
```
|
||||
|
||||
**Test** :
|
||||
```python
|
||||
>>> dijkstra(reseau, "Nice")
|
||||
{'Nice': 0, 'Monaco': 20, 'Cannes': 33, 'Grasse': 40, 'Antibes': 44, 'Menton': 30}
|
||||
```
|
||||
|
||||
### 2.3. Sélection du minimum
|
||||
|
||||
Implémenter une fonction auxiliaire pour sélectionner le sommet non visité avec la plus petite distance :
|
||||
|
||||
```python
|
||||
def selectionner_minimum(distances, non_visites):
|
||||
"""
|
||||
Sélectionne le sommet non visité avec la distance minimale.
|
||||
|
||||
:param distances: (dict) Distances actuelles
|
||||
:param non_visites: (set) Ensemble des sommets non visités
|
||||
:return: (str) Le sommet avec la distance minimale
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 3 : Reconstruction du chemin
|
||||
|
||||
### 3.1. Mémorisation des prédécesseurs
|
||||
|
||||
Pour reconstruire le chemin, il faut mémoriser par quel sommet on est passé. Modifier `dijkstra` pour retourner aussi les prédécesseurs :
|
||||
|
||||
```python
|
||||
def dijkstra_avec_chemin(reseau, depart):
|
||||
"""
|
||||
Dijkstra avec mémorisation des prédécesseurs.
|
||||
|
||||
:return: (tuple) (distances, predecesseurs)
|
||||
"""
|
||||
distances = {ville: float('inf') for ville in reseau.graphe}
|
||||
predecesseurs = {ville: None for ville in reseau.graphe}
|
||||
distances[depart] = 0
|
||||
non_visites = set(reseau.graphe.keys())
|
||||
|
||||
while non_visites:
|
||||
courant = selectionner_minimum(distances, non_visites)
|
||||
non_visites.remove(courant)
|
||||
|
||||
if distances[courant] == float('inf'):
|
||||
break
|
||||
|
||||
for voisin, poids in reseau.get_voisins(courant):
|
||||
nouvelle_distance = distances[courant] + poids
|
||||
if nouvelle_distance < distances[voisin]:
|
||||
distances[voisin] = nouvelle_distance
|
||||
predecesseurs[voisin] = courant # Mémoriser le prédécesseur
|
||||
|
||||
return distances, predecesseurs
|
||||
```
|
||||
|
||||
### 3.2. Reconstruction
|
||||
|
||||
Implémenter la fonction de reconstruction du chemin :
|
||||
|
||||
```python
|
||||
def reconstruire_chemin(predecesseurs, depart, arrivee):
|
||||
"""
|
||||
Reconstruit le chemin du départ à l'arrivée.
|
||||
|
||||
:param predecesseurs: (dict) Dictionnaire des prédécesseurs
|
||||
:param depart: (str) Ville de départ
|
||||
:param arrivee: (str) Ville d'arrivée
|
||||
:return: (list) Chemin sous forme de liste de villes
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
```
|
||||
|
||||
**Test** :
|
||||
```python
|
||||
>>> distances, pred = dijkstra_avec_chemin(reseau, "Nice")
|
||||
>>> reconstruire_chemin(pred, "Nice", "Menton")
|
||||
['Nice', 'Monaco', 'Menton']
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 4 : GPS Navigator
|
||||
|
||||
### 4.1. Classe GPS
|
||||
|
||||
Créer une classe complète de navigation :
|
||||
|
||||
```python
|
||||
class GPSNavigator:
|
||||
"""Système de navigation GPS."""
|
||||
|
||||
def __init__(self):
|
||||
self.reseau = ReseauRoutier()
|
||||
|
||||
def charger_carte(self, fichier):
|
||||
"""Charge une carte depuis un fichier."""
|
||||
# Bonus : à implémenter
|
||||
pass
|
||||
|
||||
def calculer_itineraire(self, depart, arrivee):
|
||||
"""
|
||||
Calcule l'itinéraire optimal entre deux villes.
|
||||
|
||||
:param depart: (str) Ville de départ
|
||||
:param arrivee: (str) Ville d'arrivée
|
||||
:return: (dict) Informations sur l'itinéraire
|
||||
"""
|
||||
distances, predecesseurs = dijkstra_avec_chemin(self.reseau, depart)
|
||||
|
||||
if distances[arrivee] == float('inf'):
|
||||
return {"erreur": "Aucun itinéraire trouvé"}
|
||||
|
||||
chemin = reconstruire_chemin(predecesseurs, depart, arrivee)
|
||||
|
||||
return {
|
||||
"depart": depart,
|
||||
"arrivee": arrivee,
|
||||
"distance": distances[arrivee],
|
||||
"chemin": chemin,
|
||||
"nb_etapes": len(chemin) - 1
|
||||
}
|
||||
|
||||
def afficher_itineraire(self, itineraire):
|
||||
"""Affiche l'itinéraire de manière lisible."""
|
||||
if "erreur" in itineraire:
|
||||
print(itineraire["erreur"])
|
||||
return
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"ITINÉRAIRE : {itineraire['depart']} → {itineraire['arrivee']}")
|
||||
print(f"{'='*50}")
|
||||
print(f"Distance totale : {itineraire['distance']} km")
|
||||
print(f"Nombre d'étapes : {itineraire['nb_etapes']}")
|
||||
print(f"\nChemin :")
|
||||
for i, ville in enumerate(itineraire['chemin']):
|
||||
if i < len(itineraire['chemin']) - 1:
|
||||
print(f" {i+1}. {ville} →")
|
||||
else:
|
||||
print(f" {i+1}. {ville} (arrivée)")
|
||||
print(f"{'='*50}\n")
|
||||
```
|
||||
|
||||
### 4.2. Test complet
|
||||
|
||||
```python
|
||||
# Création du GPS
|
||||
gps = GPSNavigator()
|
||||
|
||||
# Ajout des villes de la Côte d'Azur
|
||||
villes = ["Nice", "Monaco", "Menton", "Cannes", "Antibes", "Grasse", "Vence"]
|
||||
for ville in villes:
|
||||
gps.reseau.ajouter_ville(ville)
|
||||
|
||||
# Ajout des routes (distances en km)
|
||||
routes = [
|
||||
("Nice", "Monaco", 20),
|
||||
("Monaco", "Menton", 10),
|
||||
("Nice", "Cannes", 33),
|
||||
("Nice", "Antibes", 23),
|
||||
("Cannes", "Antibes", 11),
|
||||
("Cannes", "Grasse", 17),
|
||||
("Nice", "Grasse", 40),
|
||||
("Nice", "Vence", 22),
|
||||
("Grasse", "Vence", 15)
|
||||
]
|
||||
for v1, v2, dist in routes:
|
||||
gps.reseau.ajouter_route(v1, v2, dist)
|
||||
|
||||
# Calcul d'itinéraires
|
||||
itineraire = gps.calculer_itineraire("Menton", "Grasse")
|
||||
gps.afficher_itineraire(itineraire)
|
||||
```
|
||||
|
||||
**Sortie attendue** :
|
||||
```
|
||||
==================================================
|
||||
ITINÉRAIRE : Menton → Grasse
|
||||
==================================================
|
||||
Distance totale : 70 km
|
||||
Nombre d'étapes : 3
|
||||
|
||||
Chemin :
|
||||
1. Menton →
|
||||
2. Monaco →
|
||||
3. Nice →
|
||||
4. Grasse (arrivée)
|
||||
==================================================
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 5 : Améliorations (Bonus)
|
||||
|
||||
### 5.1. Itinéraire par temps de trajet
|
||||
|
||||
Modifier le système pour calculer l'itinéraire le plus rapide au lieu du plus court :
|
||||
- Stocker aussi la vitesse moyenne de chaque route
|
||||
- Calculer le temps de trajet : `temps = distance / vitesse`
|
||||
|
||||
### 5.2. Points d'intérêt
|
||||
|
||||
Ajouter la possibilité de passer par des points intermédiaires :
|
||||
```python
|
||||
gps.calculer_itineraire_via("Nice", "Menton", via=["Monaco"])
|
||||
```
|
||||
|
||||
### 5.3. Éviter certaines routes
|
||||
|
||||
Permettre d'éviter des routes (travaux, péages...) :
|
||||
```python
|
||||
gps.calculer_itineraire("Nice", "Cannes", eviter=["autoroute"])
|
||||
```
|
||||
|
||||
### 5.4. Visualisation
|
||||
|
||||
Utiliser `matplotlib` ou `networkx` pour afficher graphiquement le réseau et l'itinéraire calculé.
|
||||
|
||||
---
|
||||
|
||||
## Partie 6 : Questions de synthèse
|
||||
|
||||
1. Quelle est la complexité temporelle de l'algorithme de Dijkstra avec notre implémentation ?
|
||||
|
||||
2. Comment améliorer les performances pour de très grands graphes (millions de sommets) ?
|
||||
|
||||
3. Pourquoi Dijkstra ne fonctionne-t-il pas avec des poids négatifs ?
|
||||
|
||||
4. Quel algorithme utiliseriez-vous pour trouver le chemin passant par tous les sommets exactement une fois ?
|
||||
|
||||
---
|
||||
|
||||
## Barème indicatif
|
||||
|
||||
| Partie | Points |
|
||||
|--------|--------|
|
||||
| Partie 1 : Modélisation | 3 |
|
||||
| Partie 2 : Dijkstra | 6 |
|
||||
| Partie 3 : Reconstruction | 4 |
|
||||
| Partie 4 : GPS Navigator | 5 |
|
||||
| Partie 5 : Bonus | 2 |
|
||||
| **Total** | **20** |
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
55
Routage/animation_dijkstra.py
Normal file
55
Routage/animation_dijkstra.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import networkx as nx
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
|
||||
# Création du graphe
|
||||
G = nx.DiGraph()
|
||||
edges = [
|
||||
(0, 1, 4), (0, 2, 1),
|
||||
(2, 1, 2), (1, 3, 1),
|
||||
(2, 3, 5), (3, 4, 3)
|
||||
]
|
||||
G.add_weighted_edges_from(edges)
|
||||
|
||||
# Position des nœuds pour affichage
|
||||
pos = nx.spring_layout(G, seed=42)
|
||||
labels = {n: str(n) for n in G.nodes()}
|
||||
|
||||
# Initialisation de la figure
|
||||
fig, ax = plt.subplots(figsize=(6, 6))
|
||||
|
||||
# Algorithme de Dijkstra avec animation
|
||||
def dijkstra_animation(start_node=0):
|
||||
distances = {node: float('inf') for node in G.nodes()}
|
||||
distances[start_node] = 0
|
||||
visited = set()
|
||||
steps = []
|
||||
|
||||
while len(visited) < len(G.nodes()):
|
||||
min_node = min((node for node in distances if node not in visited), key=lambda x: distances[x])
|
||||
visited.add(min_node)
|
||||
|
||||
for neighbor in G.neighbors(min_node):
|
||||
new_distance = distances[min_node] + G[min_node][neighbor]["weight"]
|
||||
if new_distance < distances[neighbor]:
|
||||
distances[neighbor] = new_distance
|
||||
|
||||
steps.append((visited.copy(), [(min_node, v) for v in G.neighbors(min_node)]))
|
||||
|
||||
return steps
|
||||
|
||||
steps = dijkstra_animation()
|
||||
|
||||
def update(frame):
|
||||
ax.clear()
|
||||
visited, edges = steps[frame]
|
||||
node_colors = ["green" if n in visited else "lightblue" for n in G.nodes()]
|
||||
edge_colors = ["red" if (u, v) in edges else "black" for u, v in G.edges()]
|
||||
|
||||
nx.draw(G, pos, with_labels=True, labels=labels, node_size=800,
|
||||
node_color=node_colors, edge_color=edge_colors, font_size=14, font_weight="bold", ax=ax)
|
||||
edge_labels = {(u, v): G[u][v]["weight"] for u, v in G.edges()}
|
||||
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=12, ax=ax)
|
||||
|
||||
ani = animation.FuncAnimation(fig, update, frames=len(steps), repeat=False, interval=1000)
|
||||
plt.show()
|
||||
@@ -24,13 +24,13 @@ def dijkstra(g, s):
|
||||
res[IND[s]] = 0
|
||||
a_faire = [e for e in g[0]]
|
||||
while a_faire != []:
|
||||
ind_courrant = select_min(res, a_faire)
|
||||
sommet_courrant = g[0][ind_courrant]
|
||||
a_faire.remove(sommet_courrant)
|
||||
cout_courrant = res[ind_courrant]
|
||||
ind_courant = select_min(res, a_faire)
|
||||
sommet_courant = g[0][ind_courant]
|
||||
a_faire.remove(sommet_courant)
|
||||
cout_courant = res[ind_courant]
|
||||
for l in g[1]:
|
||||
if l[0]==sommet_courrant:
|
||||
cout_tmp=l[2]+cout_courrant
|
||||
if l[0]==sommet_courant:
|
||||
cout_tmp=l[2]+cout_courant
|
||||
if res[IND[l[1]]]>=cout_tmp:
|
||||
res[IND[l[1]]] = cout_tmp
|
||||
return res
|
||||
|
||||
Reference in New Issue
Block a user