Suppression temporaire des corrigés
This commit is contained in:
@@ -1,177 +0,0 @@
|
||||
# Corrigé — Exercices Programmation Dynamique
|
||||
|
||||
## Exercice 1 — L'escalier
|
||||
|
||||
**1.** Pour `n = 5` : escalier(5) = escalier(4) + escalier(3) = 5 + 3 = **8 façons**
|
||||
|
||||
**2.** La suite `escalier(n)` suit la **suite de Fibonacci** (décalée d'un rang) : 1, 2, 3, 5, 8, 13...
|
||||
|
||||
**3.** Relation de récurrence :
|
||||
```
|
||||
escalier(1) = 1
|
||||
escalier(2) = 2
|
||||
escalier(n) = escalier(n-1) + escalier(n-2) pour n > 2
|
||||
```
|
||||
|
||||
**4.** Version mémoïsation :
|
||||
|
||||
```python
|
||||
def escalier_memo(n):
|
||||
memo = {1: 1, 2: 2}
|
||||
|
||||
def escalier(k):
|
||||
if k in memo:
|
||||
return memo[k]
|
||||
memo[k] = escalier(k - 1) + escalier(k - 2)
|
||||
return memo[k]
|
||||
|
||||
return escalier(n)
|
||||
```
|
||||
|
||||
**5.** Version bottom-up :
|
||||
|
||||
```python
|
||||
def escalier_bottom_up(n):
|
||||
if n == 1:
|
||||
return 1
|
||||
tableau = [0] * (n + 1)
|
||||
tableau[1] = 1
|
||||
tableau[2] = 2
|
||||
for i in range(3, n + 1):
|
||||
tableau[i] = tableau[i - 1] + tableau[i - 2]
|
||||
return tableau[n]
|
||||
```
|
||||
|
||||
**6.** Vérification :
|
||||
|
||||
```python
|
||||
for i in range(1, 11):
|
||||
assert escalier_memo(i) == escalier_bottom_up(i), f"Erreur pour n={i}"
|
||||
print("Toutes les valeurs correspondent !")
|
||||
# Résultats : 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
|
||||
```
|
||||
|
||||
## Exercice 2 — Rendu de monnaie revisité
|
||||
|
||||
**1.** Avec les pièces [2, 5, 10] et somme = 6 : le glouton prend 5 (la plus grande pièce ≤ 6), il reste 1 à rendre, mais aucune pièce de [2, 5, 10] ne permet de rendre 1. **Le glouton échoue.**
|
||||
|
||||
**2.** Oui. La programmation dynamique explore toutes les combinaisons et trouve : 2+2+2 = **3 pièces**. La somme 6 est bien rendable, le glouton était simplement mal parti en choisissant 5 en premier.
|
||||
|
||||
**3.** `rendu_bottom_up` :
|
||||
|
||||
```python
|
||||
def rendu_bottom_up(pieces, somme):
|
||||
tableau = [float('inf')] * (somme + 1)
|
||||
tableau[0] = 0
|
||||
for s in range(1, somme + 1):
|
||||
for piece in pieces:
|
||||
if piece <= s and tableau[s - piece] + 1 < tableau[s]:
|
||||
tableau[s] = tableau[s - piece] + 1
|
||||
return tableau[somme]
|
||||
|
||||
# Tests
|
||||
print(rendu_bottom_up([2, 5, 10], 6)) # 3 (2+2+2)
|
||||
print(rendu_bottom_up([1, 3, 4], 6)) # 2 (3+3)
|
||||
print(rendu_bottom_up([1, 5, 6, 9], 11)) # 2 (5+6)
|
||||
```
|
||||
|
||||
**4.** Version avec reconstruction :
|
||||
|
||||
```python
|
||||
def rendu_avec_pieces(pieces, somme):
|
||||
tableau = [float('inf')] * (somme + 1)
|
||||
tableau[0] = 0
|
||||
derniere_piece = [-1] * (somme + 1) # mémorise quelle pièce a été utilisée
|
||||
|
||||
for s in range(1, somme + 1):
|
||||
for piece in pieces:
|
||||
if piece <= s and tableau[s - piece] + 1 < tableau[s]:
|
||||
tableau[s] = tableau[s - piece] + 1
|
||||
derniere_piece[s] = piece
|
||||
|
||||
# Reconstruction
|
||||
pieces_utilisees = []
|
||||
s = somme
|
||||
while s > 0:
|
||||
p = derniere_piece[s]
|
||||
pieces_utilisees.append(p)
|
||||
s -= p
|
||||
|
||||
return tableau[somme], pieces_utilisees
|
||||
|
||||
print(rendu_avec_pieces([1, 3, 4], 6))
|
||||
# (2, [3, 3])
|
||||
```
|
||||
|
||||
## Exercice 3 — Sac à dos : à la main et en code
|
||||
|
||||
**1.** Tableau `tableau[i][w]` :
|
||||
|
||||
objets = [(1,2), (2,5), (3,8), (4,9)], capacité = 6
|
||||
|
||||
| | w=0 | w=1 | w=2 | w=3 | w=4 | w=5 | w=6 |
|
||||
|---|-----|-----|-----|-----|-----|-----|-----|
|
||||
| i=0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| i=1 (A:1kg,2) | 0 | 2 | 2 | 2 | 2 | 2 | 2 |
|
||||
| i=2 (+B:2kg,5) | 0 | 2 | 5 | 7 | 7 | 7 | 7 |
|
||||
| i=3 (+C:3kg,8) | 0 | 2 | 5 | 8 | 10 | 13 | 15 |
|
||||
| i=4 (+D:4kg,9) | 0 | 2 | 5 | 8 | 10 | 13 | 15 |
|
||||
|
||||
**2.** Valeur maximale : **15**
|
||||
|
||||
**3.** Reconstruction depuis `tableau[4][6] = 15` :
|
||||
- `tableau[4][6] = tableau[3][6]` → D non pris, w reste 6
|
||||
- `tableau[3][6] = 15 ≠ tableau[2][6] = 7` → C pris (3kg), w = 6-3 = 3
|
||||
- `tableau[2][3] = 7 ≠ tableau[1][3] = 2` → B pris (2kg), w = 3-2 = 1
|
||||
- `tableau[1][1] = 2 ≠ tableau[0][1] = 0` → A pris (1kg), w = 0
|
||||
|
||||
Solution : **A + B + C** = 2+5+8 = 15 ✓
|
||||
|
||||
**4.** Vérification :
|
||||
|
||||
```python
|
||||
objets = [(1, 2), (2, 5), (3, 8), (4, 9)]
|
||||
valeur, choix = sac_reconstruction(objets, 6)
|
||||
print(valeur, choix) # 15, [(3, 8), (2, 5), (1, 2)]
|
||||
```
|
||||
|
||||
## Exercice 4 — Triangle de Pascal
|
||||
|
||||
**1.** Relation de récurrence :
|
||||
```
|
||||
pascal(0, 0) = 1
|
||||
pascal(n, 0) = 1 ← bord gauche
|
||||
pascal(n, n) = 1 ← bord droit
|
||||
pascal(n, k) = pascal(n-1, k-1) + pascal(n-1, k) pour 0 < k < n
|
||||
```
|
||||
|
||||
**2.** Implémentation bottom-up :
|
||||
|
||||
```python
|
||||
def triangle_pascal(n):
|
||||
triangle = []
|
||||
for ligne in range(n):
|
||||
t = [1] * (ligne + 1) # initialise avec des 1
|
||||
for k in range(1, ligne): # cases intérieures
|
||||
t[k] = triangle[ligne-1][k-1] + triangle[ligne-1][k]
|
||||
triangle.append(t)
|
||||
return triangle
|
||||
```
|
||||
|
||||
**3.** Vérification :
|
||||
|
||||
```python
|
||||
resultat = triangle_pascal(5)
|
||||
assert resultat == [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]
|
||||
print("Correct !")
|
||||
```
|
||||
|
||||
**4.** Bonus : La somme des éléments de la ligne `n` est `2ⁿ`. Par exemple, ligne 4 : 1+4+6+4+1 = 16 = 2⁴. Lien avec Fibonacci : la somme des diagonales "montantes" du triangle de Pascal donne les nombres de Fibonacci.
|
||||
|
||||
---
|
||||
|
||||
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>.
|
||||
@@ -1,194 +0,0 @@
|
||||
# Corrigé — TP Le Donjon du Dragon
|
||||
|
||||
## Partie 1 — Comprendre le problème
|
||||
|
||||
**Question 1.** Chemins de `(0,0)` à `(2,3)` (grille 3×4) en allant uniquement droite/bas :
|
||||
Il faut faire exactement 3 pas vers la droite et 2 pas vers le bas, soit C(5,2) = **10 chemins**.
|
||||
|
||||
**Question 2.** Le chemin optimal est `(0,0)→(1,0)→(1,1)→(2,1)→(2,2)→(2,3)` : 3+5+9+2+8-5 = **22** d'or.
|
||||
|
||||
| Chemin | Or total |
|
||||
|--------|----------|
|
||||
| Tout droite puis tout bas | 3-1+4+1+6-5 = **8** |
|
||||
| Bas, droite×3, bas | 3+5+9-2+6-5 = **16** |
|
||||
| Bas×2, droite×3 | 3+5-3+2+8-5 = **10** |
|
||||
| Bas, droite, bas, droite×2 | 3+5+9+2+8-5 = **22** ← optimal |
|
||||
|
||||
**Question 3.** Pour une grille `n×m`, le nombre de chemins est C(n+m-2, n-1) (combinaison : choisir quand descendre parmi tous les pas).
|
||||
|
||||
## Partie 2 — Formulation récursive
|
||||
|
||||
**Question 4.** Cas de base :
|
||||
- `donjon(i, 0)` : on ne peut aller que vers le bas → somme de la colonne 0 jusqu'à `i`
|
||||
- `donjon(0, j)` : on ne peut aller que vers la droite → somme de la ligne 0 jusqu'à `j`
|
||||
|
||||
**Question 5.** Relation générale :
|
||||
```
|
||||
donjon(i, j) = grille[i][j] + max(donjon(i-1, j), donjon(i, j-1))
|
||||
```
|
||||
*(On arrive en `(i,j)` depuis le haut ou depuis la gauche, on choisit le meilleur.)*
|
||||
|
||||
**Question 6.** Version naïve :
|
||||
|
||||
```python
|
||||
def donjon_naif(grille, i, j):
|
||||
if i == 0 and j == 0:
|
||||
return grille[0][0]
|
||||
if i == 0:
|
||||
return grille[0][j] + donjon_naif(grille, 0, j - 1)
|
||||
if j == 0:
|
||||
return grille[i][0] + donjon_naif(grille, i - 1, 0)
|
||||
return grille[i][j] + max(donjon_naif(grille, i - 1, j),
|
||||
donjon_naif(grille, i, j - 1))
|
||||
|
||||
grille = [
|
||||
[ 3, -1, 4, 1],
|
||||
[ 5, 9, -2, 6],
|
||||
[-3, 2, 8, -5]
|
||||
]
|
||||
n, m = len(grille), len(grille[0])
|
||||
print(donjon_naif(grille, n - 1, m - 1)) # 22
|
||||
```
|
||||
|
||||
## Partie 3 — Version Top-Down (mémoïsation)
|
||||
|
||||
**Question 7.** Oui, beaucoup de sous-problèmes sont recalculés. Par exemple, `donjon(1,1)` est appelé depuis `donjon(2,1)` et depuis `donjon(1,2)`.
|
||||
|
||||
```python
|
||||
compteur = 0
|
||||
|
||||
def donjon_naif_compte(grille, i, j):
|
||||
global compteur
|
||||
compteur += 1
|
||||
if i == 0 and j == 0:
|
||||
return grille[0][0]
|
||||
if i == 0:
|
||||
return grille[0][j] + donjon_naif_compte(grille, 0, j - 1)
|
||||
if j == 0:
|
||||
return grille[i][0] + donjon_naif_compte(grille, i - 1, 0)
|
||||
return grille[i][j] + max(donjon_naif_compte(grille, i - 1, j),
|
||||
donjon_naif_compte(grille, i, j - 1))
|
||||
|
||||
donjon_naif_compte(grille, 2, 3)
|
||||
print(f"Nombre d'appels : {compteur}") # bien plus que les 12 cases de la grille
|
||||
```
|
||||
|
||||
**Question 8.** Version mémoïsation :
|
||||
|
||||
```python
|
||||
def donjon_memo(grille):
|
||||
n = len(grille)
|
||||
m = len(grille[0])
|
||||
memo = {}
|
||||
|
||||
def donjon(i, j):
|
||||
if (i, j) in memo:
|
||||
return memo[(i, j)]
|
||||
if i == 0 and j == 0:
|
||||
resultat = grille[0][0]
|
||||
elif i == 0:
|
||||
resultat = grille[0][j] + donjon(0, j - 1)
|
||||
elif j == 0:
|
||||
resultat = grille[i][0] + donjon(i - 1, 0)
|
||||
else:
|
||||
resultat = grille[i][j] + max(donjon(i - 1, j), donjon(i, j - 1))
|
||||
memo[(i, j)] = resultat
|
||||
return resultat
|
||||
|
||||
return donjon(n - 1, m - 1)
|
||||
|
||||
print(donjon_memo(grille)) # 22
|
||||
```
|
||||
|
||||
**Question 9.** Les deux versions donnent 22 ✓
|
||||
|
||||
## Partie 4 — Version Bottom-Up (tableau)
|
||||
|
||||
**Question 10.** Tableau `t[i][j]` = or max depuis `(0,0)` jusqu'à `(i,j)` :
|
||||
|
||||
```
|
||||
grille : tableau :
|
||||
[ 3, -1, 4, 1] [ 3, 2, 6, 7]
|
||||
[ 5, 9, -2, 6] [ 8, 17, 15, 21]
|
||||
[-3, 2, 8, -5] [ 5, 19, 27, 22]
|
||||
```
|
||||
|
||||
**Question 11.** Implémentation :
|
||||
|
||||
```python
|
||||
def donjon_bottom_up(grille):
|
||||
n = len(grille)
|
||||
m = len(grille[0])
|
||||
tableau = [[0] * m for _ in range(n)]
|
||||
|
||||
tableau[0][0] = grille[0][0]
|
||||
|
||||
for j in range(1, m): # première ligne
|
||||
tableau[0][j] = tableau[0][j - 1] + grille[0][j]
|
||||
|
||||
for i in range(1, n): # première colonne
|
||||
tableau[i][0] = tableau[i - 1][0] + grille[i][0]
|
||||
|
||||
for i in range(1, n): # reste du tableau
|
||||
for j in range(1, m):
|
||||
tableau[i][j] = grille[i][j] + max(tableau[i - 1][j],
|
||||
tableau[i][j - 1])
|
||||
|
||||
return tableau[n - 1][m - 1]
|
||||
|
||||
print(donjon_bottom_up(grille)) # 22
|
||||
```
|
||||
|
||||
**Question 12.** Les trois versions donnent 22 ✓
|
||||
|
||||
## Partie 5 — Bonus : retrouver le chemin optimal
|
||||
|
||||
**Question 13.** Reconstruction du chemin :
|
||||
|
||||
```python
|
||||
def donjon_chemin(grille):
|
||||
n = len(grille)
|
||||
m = len(grille[0])
|
||||
tableau = [[0] * m for _ in range(n)]
|
||||
|
||||
tableau[0][0] = grille[0][0]
|
||||
for j in range(1, m):
|
||||
tableau[0][j] = tableau[0][j - 1] + grille[0][j]
|
||||
for i in range(1, n):
|
||||
tableau[i][0] = tableau[i - 1][0] + grille[i][0]
|
||||
for i in range(1, n):
|
||||
for j in range(1, m):
|
||||
tableau[i][j] = grille[i][j] + max(tableau[i - 1][j],
|
||||
tableau[i][j - 1])
|
||||
|
||||
# Reconstruction : on remonte depuis (n-1, m-1)
|
||||
chemin = []
|
||||
i, j = n - 1, m - 1
|
||||
while i > 0 or j > 0:
|
||||
chemin.append((i, j))
|
||||
if i == 0:
|
||||
j -= 1
|
||||
elif j == 0:
|
||||
i -= 1
|
||||
elif tableau[i - 1][j] > tableau[i][j - 1]:
|
||||
i -= 1
|
||||
else:
|
||||
j -= 1
|
||||
chemin.append((0, 0))
|
||||
chemin.reverse()
|
||||
|
||||
return tableau[n - 1][m - 1], chemin
|
||||
|
||||
|
||||
valeur, chemin = donjon_chemin(grille)
|
||||
print(f"Or maximal : {valeur}") # 22
|
||||
print(f"Chemin optimal : {chemin}") # [(0,0), (1,0), (1,1), (2,1), (2,2), (2,3)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
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>.
|
||||
@@ -1,190 +0,0 @@
|
||||
# Corrigé — TP L'Algorithme du Vaccin
|
||||
|
||||
## Partie 1 — Comprendre le problème
|
||||
|
||||
**Question 1.** Algorithme glouton (tri par ratio efficacité/temps décroissant) :
|
||||
|
||||
Ratios : Gamma (15,0), Delta (14,3), Epsilon (14,2), Bêta (14,0), Alpha (13,3)
|
||||
|
||||
- Prendre Gamma : 2 h utilisées, efficacité 30, reste 8 h
|
||||
- Prendre Delta : 2+7=9 h utilisées, efficacité 130, reste 1 h
|
||||
- Plus aucun anticorps ne tient en 1 h → arrêt
|
||||
|
||||
**Résultat glouton : 130** (Gamma + Delta)
|
||||
|
||||
**Question 2.** Oui : Alpha + Bêta + Gamma = 3+5+2 = 10 h, efficacité 40+70+30 = **140**. Le glouton a raté la solution optimale.
|
||||
|
||||
**Question 3.** Pour 5 anticorps : 2⁵ = 32 combinaisons. Pour 30 anticorps : 2³⁰ ≈ 1 milliard. L'approche exhaustive devient impraticable très rapidement.
|
||||
|
||||
---
|
||||
|
||||
## Partie 2 — Formulation récursive
|
||||
|
||||
**Question 4.** Cas de base :
|
||||
- `vaccin(0, t) = 0` (aucun anticorps disponible)
|
||||
- `vaccin(i, 0) = 0` (temps épuisé)
|
||||
|
||||
**Question 5.** Relation de récurrence :
|
||||
|
||||
```
|
||||
vaccin(i, t) = vaccin(i-1, t) si duree_i > t
|
||||
vaccin(i, t) = max(vaccin(i-1, t), sinon
|
||||
eff_i + vaccin(i-1, t - duree_i))
|
||||
```
|
||||
|
||||
**Question 6.** Version naïve :
|
||||
|
||||
```python
|
||||
def vaccin_naif(anticorps, i, t):
|
||||
if i == 0 or t == 0:
|
||||
return 0
|
||||
duree, eff = anticorps[i - 1]
|
||||
if duree > t:
|
||||
return vaccin_naif(anticorps, i - 1, t)
|
||||
else:
|
||||
sans = vaccin_naif(anticorps, i - 1, t)
|
||||
avec = eff + vaccin_naif(anticorps, i - 1, t - duree)
|
||||
return max(sans, avec)
|
||||
|
||||
anticorps = [(3, 40), (5, 70), (2, 30), (7, 100), (6, 85)]
|
||||
n = len(anticorps)
|
||||
print(vaccin_naif(anticorps, n, 10)) # 140
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 3 — Version Top-Down (mémoïsation)
|
||||
|
||||
**Question 7.** Oui. Par exemple, `vaccin(2, 5)` (2 premiers anticorps, 5 h restantes) peut être appelé en ne prenant pas Alpha, mais aussi après avoir pris Alpha (si on avait commencé avec 8 h). Sans mémoïsation, ce sous-problème est recalculé à chaque fois.
|
||||
|
||||
**Question 8.** Version mémoïsation :
|
||||
|
||||
```python
|
||||
def vaccin_memo(anticorps, temps_total):
|
||||
memo = {}
|
||||
|
||||
def vaccin(i, t):
|
||||
if i == 0 or t == 0:
|
||||
return 0
|
||||
if (i, t) in memo:
|
||||
return memo[(i, t)]
|
||||
duree, eff = anticorps[i - 1]
|
||||
if duree > t:
|
||||
resultat = vaccin(i - 1, t)
|
||||
else:
|
||||
sans = vaccin(i - 1, t)
|
||||
avec = eff + vaccin(i - 1, t - duree)
|
||||
resultat = max(sans, avec)
|
||||
memo[(i, t)] = resultat
|
||||
return resultat
|
||||
|
||||
return vaccin(len(anticorps), temps_total)
|
||||
|
||||
print(vaccin_memo(anticorps, 10)) # 140
|
||||
```
|
||||
|
||||
**Question 9.** Les deux versions donnent 140 ✓
|
||||
|
||||
---
|
||||
|
||||
## Partie 4 — Version Bottom-Up (tableau)
|
||||
|
||||
**Question 10.** Tableau pour Alpha (3h,40), Bêta (5h,70), Gamma (2h,30), T=6 :
|
||||
|
||||
| | t=0 | t=1 | t=2 | t=3 | t=4 | t=5 | t=6 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| i=0 (aucun) | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| i=1 (Alpha 3h, 40) | 0 | 0 | 0 | 40 | 40 | 40 | 40 |
|
||||
| i=2 (+Bêta 5h, 70) | 0 | 0 | 0 | 40 | 40 | 70 | 70 |
|
||||
| i=3 (+Gamma 2h, 30) | 0 | 0 | 30 | 40 | 40 | 70 | 70 |
|
||||
|
||||
Avec 6 h, le meilleur est Bêta seul (70), ou Gamma+Alpha ne tient pas car 2+3=5 h → efficacité 70 aussi.
|
||||
|
||||
**Question 11.** Implémentation :
|
||||
|
||||
```python
|
||||
def vaccin_bottom_up(anticorps, temps_total):
|
||||
n = len(anticorps)
|
||||
tableau = [[0] * (temps_total + 1) for _ in range(n + 1)]
|
||||
|
||||
for i in range(1, n + 1):
|
||||
duree, eff = anticorps[i - 1]
|
||||
for t in range(temps_total + 1):
|
||||
if duree > t:
|
||||
tableau[i][t] = tableau[i - 1][t]
|
||||
else:
|
||||
tableau[i][t] = max(
|
||||
tableau[i - 1][t],
|
||||
eff + tableau[i - 1][t - duree]
|
||||
)
|
||||
|
||||
return tableau[n][temps_total]
|
||||
|
||||
print(vaccin_bottom_up(anticorps, 10)) # 140
|
||||
```
|
||||
|
||||
**Question 12.** Les trois versions donnent 140 ✓
|
||||
|
||||
---
|
||||
|
||||
## Partie 5 — Reconstruction de la solution
|
||||
|
||||
**Question 13.** Reconstruction :
|
||||
|
||||
```python
|
||||
def vaccin_reconstruction(anticorps, temps_total):
|
||||
n = len(anticorps)
|
||||
tableau = [[0] * (temps_total + 1) for _ in range(n + 1)]
|
||||
|
||||
for i in range(1, n + 1):
|
||||
duree, eff = anticorps[i - 1]
|
||||
for t in range(temps_total + 1):
|
||||
if duree > t:
|
||||
tableau[i][t] = tableau[i - 1][t]
|
||||
else:
|
||||
tableau[i][t] = max(
|
||||
tableau[i - 1][t],
|
||||
eff + tableau[i - 1][t - duree]
|
||||
)
|
||||
|
||||
# Reconstruction : on remonte le tableau
|
||||
choisis = []
|
||||
t = temps_total
|
||||
for i in range(n, 0, -1):
|
||||
if tableau[i][t] != tableau[i - 1][t]:
|
||||
choisis.append(anticorps[i - 1])
|
||||
t -= anticorps[i - 1][0]
|
||||
|
||||
return tableau[n][temps_total], choisis
|
||||
|
||||
|
||||
efficacite, choix = vaccin_reconstruction(anticorps, 10)
|
||||
print(f"Efficacité maximale : {efficacite}") # 140
|
||||
print(f"Anticorps choisis : {choix}") # [(3,40), (5,70), (2,30)] → Alpha + Bêta + Gamma
|
||||
```
|
||||
|
||||
**Question 14.** Vérification :
|
||||
- Alpha (3h) + Bêta (5h) + Gamma (2h) = **10 h** ≤ 10 h ✓
|
||||
- 40 + 70 + 30 = **140** ✓
|
||||
|
||||
**Question 15.** Complexité :
|
||||
- **Temps : O(n × T)** — on remplit un tableau de n+1 lignes et T+1 colonnes
|
||||
- **Espace : O(n × T)** — pour stocker le tableau
|
||||
|
||||
Avec n = nombre d'anticorps et T = temps total disponible.
|
||||
|
||||
---
|
||||
|
||||
## Partie 6 — Bonus : contraintes supplémentaires
|
||||
|
||||
**Question 16.** Pour gérer l'incompatibilité Alpha/Gamma, on peut ajouter une dimension à l'état : au lieu de `vaccin(i, t)`, on utilise `vaccin(i, t, alpha_pris)` où `alpha_pris` vaut 1 si Alpha a déjà été sélectionné, 0 sinon. Si `alpha_pris == 1` et que l'anticorps courant est Gamma (ou vice-versa), on interdit sa sélection.
|
||||
|
||||
Cette approche généralise naturellement : chaque contrainte d'incompatibilité entre deux objets peut être encodée comme une variable booléenne supplémentaire dans l'état. La complexité devient O(n × T × 2^k) où k est le nombre de contraintes d'incompatibilité.
|
||||
|
||||
---
|
||||
|
||||
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>.
|
||||
Reference in New Issue
Block a user