Exercices pour s'entraîner☘
Prenez l'habitude de revenir vous entraîner régulièrement avec ces exercices tout au long de l'année.
Les exercices proposés dans cette page ont tous pour objectif d'implémenter une structure de graphe, de différentes manières. Les questions sont volontairement redondantes d'un exercice à l'autre et vous rappelleront le TP d'implémentation travaillé précédemment.
Vous vous limiterez toutefois à la programmation des méthodes non triviales. Libre à vous de programmer les autres ensuite.
Méthodes autorisées
Les méthodes usuelles sur les listes Python sont autorisées, à savoir :
.append()
;.pop()
;.remove()
;.index()
;
ProgA05.51 - Graphe pondéré non orienté☘
Téléchargez le fichier « à trous » graphes_ponderes.py
(clic droit -> [Enregistrer la cible du lien sous]) et enregistrez-le
dans le dossier [Mes_modules]
.
Les objets de la classe GraphePondere
sont munis d'un unique attribut :
graphe_dico
initialisé à None
par défaut. Cet attribut est un dictionnaire
contenant, pour chaque sommet du graphe, un dictionnaires dont les clefs
sont les voisins du sommet et les valeurs sont les poids des arêtes
correspondantes.
Exemple d'initialisation
Le graphe : sera implémenté de la façon suivante :
1 2 3 4 5 6 7 |
|
Complétez les méthodes de classe suivantes :
-
.__init__()
: initialisation de l'attributgraphe_dico
.Une réponse
6 7 8 9 10 11 12 13 14 15 16
def __init__(self, dico=None): """ dico - dict, dictionnaire tel que: les clefs sont les sommets du graphe les valeurs sont un dictionnaire dont : les clefs sont les voisins du sommet les valeurs sont les poids des arêtes correspondantes """ if dico is None: dico = {} self.graphe_dico = dico
-
.sommets()
: renvoie un tableau des sommets du graphe.Exemple de test
>>> G.sommets() ['A', 'B', 'C', 'D', 'E', 'F']
Une réponse
18 19
def sommets(self): return list(self.graphe_dico.keys())
-
.aretes()
: renvoie un tableau des arêtes du graphe. Ces arêtes sont définies sous la forme d'un couple(sommet_1, sommet_2)
.Exemple de test
>>> G.aretes() [('A', 'B'), ('A', 'C'), ('B', 'D'), ('B', 'E'), ('B', 'F'), ('C', 'D'), ('C', 'E'), ('C', 'F'), ('D', 'E'), ('E', 'F')]
Une réponse
21 22 23 24 25 26 27 28 29 30
def aretes(self): """ Sortie: tableau des arêtes, sans doublons """ tab = [] for s1 in self.graphe_dico.keys(): for s2 in self.graphe_dico[s1].keys(): if (s1, s2) not in tab and (s2, s1) not in tab : tab.append( (s1, s2) ) return tab
-
.aretes_ponderees()
: renvoie un dictionnaire dont les clefs sont les arêtes du graphe et les valeurs sont les poids associés à ces arêtes.Exemple de test
>>> G.aretes_ponderees() {('A', 'B'): 5, ('A', 'C'): 6, ('B', 'D'): 3, ('B', 'E'): 4, ('B', 'F'): 3, ('C', 'D'): 6, ('C', 'E'): 8, ('C', 'F'): 3, ('D', 'E'): 2, ('E', 'F'): 4}
Une réponse
32 33 34 35 36 37 38 39 40 41
def aretes_ponderees(self): """ Sortie: dictionnaire dont les clefs sont les arêtes et dont les valeurs sont les poids associés """ dico = {} for arete in self.aretes(): (s1, s2) = arete dico[arete] = self.graphe_dico[s1][s2] return dico
-
.__str__()
: renvoie une chaîne de caractères compatible avec le logiciel Graphviz.Exemple d'affichage
Avec l'exemple de graphe proposé au début de cette partie, on obtiendra l'affichage suivant :
>>> print(G) graph G { A -- B [label=5] ; A -- C [label=6] ; B -- D [label=3] ; B -- E [label=4] ; B -- F [label=3] ; C -- D [label=6] ; C -- E [label=8] ; C -- F [label=3] ; D -- E [label=2] ; E -- F [label=4] ; }
Une réponse
43 44 45 46 47 48 49
def __str__(self): result = "graph G {\n" dico = self.aretes_ponderees() for arete in dico : (s1, s2) = arete result += f"{s1} -- {s2} [label={dico[arete]}] ;\n" return result+"}"
-
.voisins()
: renvoie le tableau des voisins du sommet passé en paramètre.
Si ce sommet n'appartient pas au graphe, une erreur d'assertion doit survenir.Exemple de test
>>> G.voisins('A') ['B', 'C'] >>> G.voisins('K') AssertionError: le sommet K n'appartient pas au graphe
Une réponse
51 52 53
def voisins(self, s): assert s in self.graphe_dico.keys(), f"le sommet {s} n'appartient pas au graphe" return list(self.graphe_dico[s].keys())
-
.voisins_poids()
: renvoie un dictionnaire dont les clefs sont les voisins du sommet passé en paramètre et les valeurs sont les poids associés.
Si ce sommet n'appartient pas au graphe, une erreur d'assertion doit survenir.Exemple de test
>>> G.voisins_poids('A') {'B': 5, 'C': 6} >>> G.voisins_poids('K') AssertionError: le sommet K n'appartient pas au graphe
Une réponse
54 55 56
def voisins_poids(self, s): assert s in self.graphe_dico.keys(), f"le sommet {s} n'appartient pas au graphe" return self.graphe_dico[s]
-
.matrice()
: renvoie la matrice de pondération du graphe, ainsi que le tableau des étiquettes des sommets afin de pouvoir établir une correspondance entre étiquette et indice dans la matrice.Exemple de test
>>> tab, mat = G.matrice() >>> print(tab) ['A', 'B', 'C', 'D', 'E', 'F'] >>> for ligne in mat: ... print(ligne) [0, 5, 6, 0, 0, 0] [5, 0, 0, 3, 4, 3] [6, 0, 0, 6, 8, 3] [0, 3, 6, 0, 2, 0] [0, 4, 8, 2, 0, 4] [0, 3, 3, 0, 4, 0]
Une réponse
60 61 62 63 64 65 66 67
def matrice(self): nb_sommets = len(self.graphe_dico) mat = [[0]*nb_sommets for i in range(nb_sommets)] tab_sommets = self.sommets() for i in range(nb_sommets): for sommet in self.graphe_dico[tab_sommets[i]]: mat[i][tab_sommets.index(sommet)] = self.graphe_dico[tab_sommets[i]][sommet] return tab_sommets, mat
ProgA05.52 - Graphe non pondéré défini par une matrice☘
Téléchargez le fichier « à trous » ProgA05.52.py
(clic droit -> [Enregistrer la cible du lien sous]) et enregistrez-le
dans le dossier [Mes_modules]
.
Les objets de la classe GrapheMatrice
sont munis de deux attributs :
matrice
qui est un tableau de tableaux d'entiers valant0
ou1
.
Ce tableau carré représente la matrice d'adjacence d'un graphe.sommets
qui est un tableau des étiquettes des sommets, initialisé àNone
par défaut. Cet attribut fait correspondre chaque indice de ligne dematrice
à une étiquette. Si le tableau d'étiquette n'est pas fourni, les étiquettes seront les entiers de0
àn-1
, oùn
est le nombre de lignes dematrice
.
Exemples d'initialisation
Le graphe orienté : sera implémenté de la façon suivante :
1 2 3 4 5 6 7 8 9 |
|
Le graphe non orienté : sera implémenté de la façon suivante :
1 2 3 4 5 6 7 8 9 |
|
Attention
La classe GrapheMatrice
doit pouvoir être utilisée pour implémenter
des graphes orientés comme non orientés.
Complétez les méthodes de classe suivantes :
-
.__init__()
: initialisation de l'attributgraphe_dico
.
Effectuez des tests d'assertion pour vérifier que la matrice est carrée et que le nombre d'étiquettes convient.Une réponse
6 7 8 9 10 11 12 13 14 15 16 17 18
def __init__(self, matrice, tab_sommets=None): """ matrice - list, tableau carré de n tableaux ayant n éléments tab_sommets - list, tableau des étiquettes des sommets, entiers de 0 à n-1 par défaut """ assert len(matrice) == len(matrice[0]), "La matrice n'est pas carrée" self.matrice = matrice if tab_sommets is None: self.sommets = list(range(len(matrice))) else: self.sommets = tab_sommets assert len(self.matrice) == len(self.sommets), "Le nombre de sommets de convient pas"
-
.est_oriente()
: renvoieTrue
si la matrice est celle d'un graphe orienté,False
sinon.Exemple de test
>>> G1.est_oriente() True >>> G2.est_oriente() False
Une réponse
21 22 23 24 25 26
def est_oriente(self): for i in range(len(self.matrice)): for j in range(i, len(self.matrice)): if self.matrice[i][j] != self.matrice[j][i]: return True return False
-
.indices_sommets()
: renvoie un dictionnaire qui, à chaque indice, associe l'étiquette correspondante.Exemple de test
>>> G1.indices_sommets() {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F'}
Une réponse
18 19
def indices_sommets(self): return {i: self.sommets[i] for i in range(len(self.sommets))}
-
Il faut programmer des fonctions permettant de renvoyer le tableau des arêtes dans le cas d'un graphe non orienté, et des arcs dans le cas d'un graphe orienté.
-
.aretes()
: renvoie un tableau des arêtes du graphe.
Ces arêtes sont définies sous la forme d'un couple(sommet_1, sommet_2)
.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe orienté.Exemple de test
>>> G1.aretes() AssertionError: Le graphe est orienté, il a des arcs, pas des arêtes >>> G2.aretes() [('A', 'B'), ('A', 'C'), ('A', 'F'), ('B', 'C'), ('B', 'E'), ('D', 'E'), ('E', 'F')]
-
.arcs()
: renvoie un tableau des arcs du graphe.
Ces arcs sont définis sous la forme d'un couple(sommet_1, sommet_2)
.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe non orienté.Exemple de test
>>> G1.arcs() [('A', 'B'), ('A', 'C'), ('B', 'C'), ('D', 'A'), ('D', 'C'), ('E', 'A'), ('E', 'C'), ('F', 'E')] >>> G2.arcs() AssertionError: Le graphe n'est pas orienté, il a des arêtes, pas des arcs
-
Une proposition de solution, qui évite des copier/coller de code.
Une réponse
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
def liaisons(self, oriente): tab = [] for i in range(len(self.matrice)): for j in range(len(self.matrice[0])): if self.matrice[i][j] != 0: if oriente or (not oriente and j>i) : tab.append( (self.sommets[i], self.sommets[j]) ) return tab def aretes(self): """ Sortie: tableau des arêtes, sans doublons """ assert not self.est_oriente(), "Le graphe est orienté, il a des arcs, pas des arêtes" return self.liaisons(False) def arcs(self): """ Sortie: tableau des arcs dans le cas d'un graphe orienté """ assert self.est_oriente(), "Le graphe n'est pas orienté, il a des arêtes, pas des arcs" return self.liaisons(True)
-
-
.__str__()
: renvoie une chaîne de caractères compatible avec le logiciel Graphviz.Exemple d'affichage
>>> print(G1) digraph G { A -> B ; A -> C ; B -> C ; D -> A ; D -> C ; E -> A ; E -> C ; F -> E ; } >>> print(G2) graph G { A -- B ; A -- C ; A -- F ; B -- C ; B -- E ; D -- E ; E -- F ; }
Une réponse
59 60 61 62 63 64 65 66 67 68 69 70
def __str__(self): oriente = self.est_oriente() if oriente: result = "digraph G {\n" fleche = "->" else: result = "graph G {\n" fleche = "--" for arete in self.liaisons(oriente): result += f"{arete[0]} {fleche} {arete[1]} ;\n" return result+"}"
-
Il faut programmer des fonctions permettant de renvoyer les dictionnaires des voisins, des successeurs, selon le type de graphe.
-
.voisins()
: renvoie le tableau des voisins du sommet passé en paramètre.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe orienté.Exemple de test
>>> G1.voisins('A') AssertionError: Le graphe est orienté, recherchez plutôt les successeurs (ou prédécesseurs) >>> G2.voisins('A') ['B', 'C', 'F']
-
.successeurs()
: renvoie le tableau des successeurs du sommet passé en paramètre.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe non orienté.Exemple de test
>>> G1.successeurs('A') ['B', 'C'] >>> G2.successeurs('A') AssertionError: Le graphe n'est pas orienté, recherchez plutôt les voisins
-
Une proposition de solution, qui évite des copier/coller de code.
Une réponse
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
def relies_a(self, s): assert s in self.sommets, f"le sommet {s} n'appartient pas au graphe" indice = self.sommets.index(s) tab = [] for i in range(len(self.matrice[indice])): if self.matrice[indice][i] != 0: tab.append(self.sommets[i]) return tab def voisins(self, s): assert not self.est_oriente(), "Le graphe est orienté, recherchez plutôt les successeurs (ou prédécesseurs)" return self.relies_a(s) def successeurs(self, s): assert self.est_oriente(), "Le graphe n'est pas orienté, recherchez plutôt les voisins" return self.relies_a(s)
-
-
.predecesseurs()
: renvoie le tableau des prédécesseurs du sommet passé en paramètre.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe non orienté.Exemple de test
>>> G1.predecesseurs('A') ['D', 'E'] >>> G2.predecesseurs('A') AssertionError: Le graphe n'est pas orienté, recherchez plutôt les voisins
Une réponse
93 94 95 96 97 98 99 100 101
def predecesseurs(self, s): assert self.est_oriente(), "Le graphe n'est pas orienté, recherchez plutôt les voisins" assert s in self.sommets, f"le sommet {s} n'appartient pas au graphe" indice = self.sommets.index(s) tab = [] for i in range(len(self.matrice[indice])): if self.matrice[i][indice] != 0: tab.append(self.sommets[i]) return tab
-
.dico_voisins()
: renvoie un dictionnaire dont les clefs sont les sommets du graphe et les valeurs associées sont les voisins de ce sommet dans le cas d'un graphe non orienté et les successeurs de ce sommet dans le cas d'un graphe orienté.Exemple de test
>>> G1.dico_voisins() {'A': ['B', 'C'], 'B': ['C'], 'C': [], 'D': ['A', 'C'], 'E': ['A', 'C'], 'F': ['E']} >>> G2.dico_voisins() {'A': ['B', 'C', 'F'], 'B': ['A', 'C', 'E'], 'C': ['A', 'B'], 'D': ['E'], 'E': ['B', 'D', 'F'], 'F': ['A', 'E']}
Une réponse
104 105 106 107 108 109 110 111
def dico_voisins(self): dico = {} for i in range(len(self.matrice)): dico[self.sommets[i]] = [] for j in range(len(self.matrice[0])): if self.matrice[i][j] != 0: dico[self.sommets[i]].append(self.sommets[j]) return dico
Une autre réponse
104 105 106 107 108 109
def dico_voisins2(self): dico = {} oriente = self.est_oriente() for sommet in self.sommets: dico[sommet] = self.relies_a(sommet) return dico
ProgA05.53 - Graphe pondéré défini par une matrice☘
Téléchargez le fichier « à trous » ProgA05.53.py
(clic droit -> [Enregistrer la cible du lien sous]) et enregistrez-le
dans le dossier [Mes_modules]
.
Les objets de la classe GrapheMatricePondere
sont munis de deux attributs :
matrice
qui est un tableau de tableaux d'entiers .
Ce tableau carré représente la matrice de pondération d'un graphe.sommets
qui est un tableau des étiquettes des sommets, initialisé àNone
par défaut. Cet attribut fait correspondre chaque indice de ligne dematrice
à une étiquette. Si le tableau d'étiquette n'est pas fourni, les étiquettes seront les entiers de0
àn-1
, oùn
est le nombre de lignes dematrice
.
Exemple d'initialisation
Le graphe orienté : sera implémenté de la façon suivante :
1 2 3 4 5 6 7 |
|
Le graphe non orienté : sera implémenté de la façon suivante :
1 2 3 4 5 6 7 8 9 |
|
Attention
La classe GrapheMatricePondere
doit pouvoir être utilisée pour
implémenter des graphes orientés comme non orientés.
Complétez les méthodes de classe du programme en adaptant le code réalisé dans l'exercice précédent.
-
.__init__()
: initialisation de l'attributgraphe_dico
.
Effectuez des tests d'assertion pour vérifier que la matrice est carrée et que le nombre d'étiquettes convient. -
.est_oriente()
: renvoieTrue
si la matrice est celle d'un graphe orienté,False
sinon.Exemple de test
>>> G3.est_oriente() True >>> G4.est_oriente() False
-
.indices_sommets()
: renvoie un dictionnaire qui, à chaque indice, associe l'étiquette correspondante.Exemple de test
>>> G3.indices_sommets() {0: 'Tata', 1: 'Titi', 2: 'Toto', 3: 'Tutu'}
-
Il faut programmer des fonctions permettant de renvoyer le tableau des arêtes dans le cas d'un graphe non orienté, et des arcs dans le cas d'un graphe orienté.
-
.aretes()
: renvoie un dictionnaire dont les clefs sont les arêtes du graphe et les valeurs sont les pondérations associées à cette arête.
Ces arêtes sont définies sous la forme d'un couple(sommet_1, sommet_2)
.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe orienté.Exemple de test
>>> G3.aretes() AssertionError: Le graphe est orienté, il a des arcs, pas des arêtes >>> G4.aretes() {('A', 'B'): 5, ('A', 'C'): 6, ('B', 'D'): 3, ('B', 'E'): 4, ('B', 'F'): 3, ('C', 'D'): 6, ('C', 'E'): 8, ('C', 'F'): 3, ('D', 'E'): 2, ('E', 'F'): 4}
-
.arcs()
: renvoie un dictionnaire dont les clefs sont les arcs du graphe et les valeurs sont les pondérations associées à cet arc.
Ces arcs sont définis sous la forme d'un couple(sommet_1, sommet_2)
.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe non orienté.Exemple de test
>>> G3.arcs() {('Tata', 'Titi'): 2, ('Tata', 'Toto'): 7, ('Titi', 'Tata'): 3, ('Titi', 'Tutu'): 4, ('Toto', 'Titi'): 5, ('Tutu', 'Tata'): 1} >>> G4.arcs() AssertionError: Le graphe n'est pas orienté, il a des arêtes, pas des arcs
-
-
.__str__()
: renvoie une chaîne de caractères compatible avec le logiciel Graphviz.Exemple d'affichage
>>> print(G3) digraph G { Tata -> Titi [label=2] ; Tata -> Toto [label=7] ; Titi -> Tata [label=3] ; Titi -> Tutu [label=4] ; Toto -> Titi [label=5] ; Tutu -> Tata [label=1] ; } >>> print(G4) graph G { A -- B [label=5] ; A -- C [label=6] ; B -- D [label=3] ; B -- E [label=4] ; B -- F [label=3] ; C -- D [label=6] ; C -- E [label=8] ; C -- F [label=3] ; D -- E [label=2] ; E -- F [label=4] ; }
-
Il faut programmer des fonctions permettant de renvoyer les dictionnaires des voisins, des successeurs, selon le type de graphe.
-
.voisins()
: renvoie le tableau des voisins du sommet passé en paramètre.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe orienté.Exemple de test
>>> G3.voisins('Toto') AssertionError: Le graphe est orienté, recherchez plutôt les successeurs (ou prédécesseurs) >>> G4.voisins('Toto') AssertionError: le sommet Toto n'appartient pas au graphe >>> G4.voisins('A') ['B', 'C']
-
.successeurs()
: renvoie le tableau des successeurs du sommet passé en paramètre.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe non orienté.Exemple de test
>>> G3.successeurs('A') AssertionError: le sommet A n'appartient pas au graphe >>> G3.successeurs('Tata') ['Titi', 'Toto'] >>> G4.successeurs('A') AssertionError: Le graphe n'est pas orienté, recherchez plutôt les voisins
-
-
.predecesseurs()
: renvoie le tableau des prédécesseurs du sommet passé en paramètre.
Un test d'assertion est nécessaire pour le cas où cette méthode est appelée sur un graphe non orienté.Exemple de test
>>> G3.predecesseurs('Tata') ['Titi', 'Tutu'] >>> G4.predecesseurs('A') AssertionError: Le graphe n'est pas orienté, recherchez plutôt les voisins
-
.dico_voisins()
: renvoie un dictionnaire dont les clefs sont les sommets du graphe et les valeurs associées sont les dictionnaires associant les voisins (les successeurs dans le cas d'un graphe orienté) de ce sommet, eux-mêmes associés au poids de l'arête (de l'arc) les reliant. dans le cas d'un graphe non orienté et les successeurs de ce sommet.Exemple de test
>>> G3.dico_voisins() {'Tata': {'Titi': 2, 'Toto': 7}, 'Titi': {'Tata': 3, 'Tutu': 4}, 'Toto': {'Titi': 5}, 'Tutu': {'Tata': 1}} >>> G4.dico_voisins() {'A': {'B': 5, 'C': 6}, 'B': {'A': 5, 'D': 3, 'E': 4, 'F': 3}, 'C': {'A': 6, 'D': 6, 'E': 8, 'F': 3}, 'D': {'B': 3, 'C': 6, 'E': 2}, 'E': {'B': 4, 'C': 8, 'D': 2, 'F': 4}, 'F': {'B': 3, 'C': 3, 'E': 4}}
Une proposition de solution☘
Une réponse
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
|