CORRIG´ E DS n°2 (X PSI 2015)
1 import random
2 from math import exp, log
3
4 ############
5 # Partie I #
6 ############
7 import random
8 from math import exp, log
9
10 ############
11 # Partie I #
12 ############
13
14 # ---
15 # Question 1
16 # ---
17
18 def creerListeVide(n):
19 # Si l'on utilise la proc´edure de l'´enonc´e:
20 # lst = creerTableau(n+1)
21 # En Python:
22 lst = [None] * (n+1)
23 lst[0] = 0
24 return lst
25
26 # ---
27 # Question 2
28 # ---
29
30 def estDansListe(lst, x):
31 # Bien sˆur, on n'a pas le droit d'utiliser la fonction in de Python!
32 for i in range(1, lst[0]+1):
33 if lst[i] == x:
34 return True
35 return False
36
37 # Cette fonction est de complexit´e O(m), o`u m est le nombre d'´el´ements de
38 # la liste
39
40 # ---
41 # Question 3
42 # ---
43
44 def ajouteDansListe(lst, x):
45 if not estDansListe(lst, x):
46 lst[0] += 1
47 lst[lst[0]] = x
48
49 # Si la liste est pleine avant l'appel, cette proc´edure provoque une erreur
50
51 # La complexit´e de cette fonction est la mˆeme que celle de la fonction
52 # estDAnsListe i.e en O(m) o`u m est la taille de la liste
53
54 ############
55 #Partie II #
56 ############
57
58 # ---
59 # Question 4
60 # ---
61
62 plan1 = [ [5, 7],
63 [2, 2, 3, None, None],
64 [3, 1, 3, 5, None],
65 [4,1,2,4,5],
66 [2,3,5,None, None],
67 [3,2,3,4, None] ]
68
69 plan2 = [ [5, 4],
70 [1, 2, None, None, None],
71 [3, 1, 3, 4, None],
72 [1, 2, None, None, None],
73 [2, 2, 5, None, None],
74 [1, 4, None, None, None] ]
75
76 # ---
77 # Question 5
78 # ---
79
80 def creerPlanSansRoute(n):
81 lst = creerListeVide(n)
82 lst[0] = [n, 0]
83 for i in range(1, n+1):
84 lst[i] = creerListeVide(n-1)
85 return lst
86
87 # ---
88 # Question 6
89 # ---
90
91 def estVoisine(plan, x, y):
92 return estDansListe(plan[x], y)
93
94 # ---
95 # Question 7
96 # ---
97
98 def ajouteRoute(plan, x, y):
99 if not estVoisine(plan, x, y):
100 plan[0][1] += 1
101 ajouteDansListe(plan[x], y)
102 ajouteDansListe(plan[y], x)
103
104 # Il n'y a pas de risque de d´epassement de la capacit´e des listes
105 # puisqu'on n'ajoute pas de nouvelle ville
106
107 # ---
108 # Question 8
109 # ---
110
111 def afficheToutesLesRoutes(plan):
112 n, m = plan[0]
113 print('Ce plan contient', n, 'routes:')
114 for x in range(1, n+1):
115 for i in range(1, plan[x][0] + 1):
116 y = plan[x][i]
117 if x < y:
118 print(' (',x,'-',y,')', end=' ')
119 print('\n')
120
121 # Complexit´e: dans le parcours du plan, chacune des n villes est parcourue
122 # une fois et `a chaque fois la liste des villes voisines est parcourue. Comme
123 # il y a m routes `a deux sens le total des longueurs de ces listes est ´egal `a
124 # 2m soit au total une complexit´e en O(n+2m).
125
126 #############
127 #Partie III #
128 #############
129
130 # ---
131 # Question 9
132 # ---
133
134 def entierAleatoire(k):
135 return random.randint(1,k)
136
137 def coloriageAleatoire(plan, couleur, k, s, t):
138 for i in range(1, plan[0][0] + 1):
139 couleur[i] = entierAleatoire(k)
140 couleur[s] = 0
141 couleur[t] = k+1
142
143 # ---
144 # Question 10
145 # ---
146
147 def voisinesDeCouleur(plan, couleur, i, c):
148 lst = creerListeVide(plan[0][0])
149 for j in range(1, plan[i][0]+1):
150 y = plan[i][j]
151 if couleur[y] == c:
152 ajouteDansListe(lst, y)
153 return lst
154
155 # ---
156 # Question 11
157 # ---
158
159 # La version ci-dessous n'utilise pas la proc´edure pr´ec´edente
160
161 def voisinesDeLaListeDeCouleur(plan, couleur, liste, c):
162 lst = creerListeVide(plan[0][0])
163 for i in range(1, liste[0]+1):
164 x = liste[i]
165 for j in range(1, plan[x][0]+1):
166 y = plan[x][j]
167 if couleur[y] == c:
168 ajouteDansListe(lst, y)
169 return lst
170
171 # Complexit´e de cette version:
172 # Comme dans la question 8, les deux boucles sur i et j conduisent `a n+2m
173 # op´erations au maximum. Mais `a chaque fois on peut ˆetre amen´e `a ajouter un
174 # ´el´ement dans la liste lst, ce qui peut faire n op´erations.
175 # D'o`u une complexit´e totale en O(n(n+2m))=O(n(n+m)).
176
177 '''
178 # La version ci-dessous utilise la proc´edure pr´ec´edente
179 # mais est de complexit´e plus grande, car `a l'int´erieur de la
180 # boucle int´erieure il y a des parcours de listes en plus.
181
182 def voisinesDeLaListeDeCouleur(plan, couleur, liste, c):
183 lst = creerListeVide(plan[0][0])
184 for i in range(1, liste[0]+1):
185 lstVoisines = voisinesDeCouleur(plan, couleur, liste[i], c)
186 for j in range(1, lstVoisines[0]+1):
187 ajouteDansListe(lst, lstVoisines[j])
188 return lst
189 '''
190
191 # ---
192 # Question 12
193 # ---
194
195 def existeCheminArcEnCiel(plan, couleur, k, s, t):
196 liste = creerListeVide(plan[0][0])
197 ajouteDansListe(liste, s)
198 for c in range(1, k+2):
199 liste = voisinesDeLaListeDeCouleur(plan, couleur, liste, c)
200 if liste[0] == 0:
201 return False
202 return True
203
204 # La fonction voisinesDeLaListeDeCouleur est appel´ee k fois donc la
205 # complexit´e de la proc´edure pr´ec´edente est en O(kn(n+m)).
206
207 ############
208 #Partie IV #
209 ############
210
211 # ---
212 # Question 13
213 # ---
214
215 def existeCheminSimple(plan, k, s, t):
216 couleur = creerListeVide(plan[0][0])
217 for i in range(k**k):
218 coloriageAleatoire(plan, couleur, k, s, t)
219 if existeCheminArcEnCiel(plan, couleur, k, s, t):
220 return True
221 return False
222
223 # La cr´eation du tableau couleur est de complexit´e O(n) et celle de la focntion
224 # coloriageAleatoire aussi
225 # Mais la fonction existeCheminArcEnCiel qui est ex´ecut´ee k**k fois a une
226 # complexit´e en O(kn(n+m)) donc la fonction pr´ec´edente a une complexit´e en
227 # O(k**(k+1)n(n+m))
228
229 # ---
230 # Question 14
231 # ---
232
233 # Pour obtenir le d´etail d'un chemin qui convient, on modifie les proc´edures
234 # pr´ec´edentes de fac¸on `a stocker non seulement les villes, mais aussi le
235 # chemin suivi depuis le sommet de d´epart pour y parvenir. On remplacera donc
236 # chaque sommet x par la liste [x, chemin] o`u chemin est la liste des sommets entre
237 # le d´epart et x
238
239 def voisinesDeLaListeDeCouleur2(plan, couleur, liste, c):
240 lst = creerListeVide(plan[0][0])
241 for i in range(1, liste[0]+1):
242 x = liste[i][0]
243 for j in range(1, plan[x][0]+1):
244 y = plan[x][j]
245 if couleur[y] == c:
246 ajouteDansListe(lst, [y, liste[i][1]+[y]])
247 return lst
248
249 def existeCheminArcEnCiel2(plan, couleur, k, s, t):
250 liste = creerListeVide(plan[0][0])
251 ajouteDansListe(liste, [s, [s]])
252 for c in range(1, k+2):
253 liste = voisinesDeLaListeDeCouleur2(plan, couleur, liste, c)
254 if liste[0] == 0:
255 return False, []
256 return True, liste[1][1]
257
258 def existeCheminSimple2(plan, k, s, t):
259 couleur = creerListeVide(plan[0][0])
260 for i in range(k**k):
261 coloriageAleatoire(plan, couleur, k, s, t)
262 test, lst = existeCheminArcEnCiel2(plan, couleur, k, s, t)
263 if test:
264 return True, lst
265 return False, []
266
267 #############################################################
268 # TESTS
269
270 # Question 6:
271 print('Question 6:',estVoisine(plan1, 1, 3))
272 print('Question 6:',estVoisine(plan1, 1, 4),'\n')
273
274 # Question 8:
275 afficheToutesLesRoutes(plan1)
276
277 # Question 13:
278 s = 1 ; t = 3 ; k = 3
279 nbessais = 50000
280 nbreussi = 0
281 for i in range(nbessais):
282 if existeCheminSimple(plan1, k, s, t):
283 nbreussi += 1
284 proba = 1 - exp(k**k*log(1-k**(-k)))
285 print('Taux de succ`es dans existeCheminSimple:',nbreussi/nbessais, 'proba th´eorique=', '%.5f'%proba,
286
287 # Question 14:
288 s = 1 ; t = 3 ; k = 3
289 reussi = False
290 while not reussi: # s'il n'existe pas de chemin, boucle infinie! `a am´eliorer.
291 reussi, lst = existeCheminSimple2(plan1, k, s, t)
292 print('Chemin pour aller de',s,'`a',t,'en passant par',k,'villes:',lst) Question 6: True
Question 6: False
Ce plan contient 5 routes:
( 1 - 2 ) ( 1 - 3 ) ( 2 - 3 ) ( 2 - 5 ) ( 3 - 4 ) ( 3 - 5 ) ( 4 - 5 ) Taux de succ`es dans existeCheminSimple: 0.63662 proba th´eorique= 0.63904 Chemin pour aller de 1 `a 3 en passant par 3 villes: [1, 2, 5, 4, 3]
⋆ ⋆ ⋆ ⋆
⋆ ⋆ ⋆
⋆ ⋆
⋆