Files
1ereNSI/gloutons/EXERCICES.md
T

374 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
### Exercices - Algorithmes Gloutons
**Niveaux de difficulté :** Facile | Moyen | Difficile
---
## Exercice 1 (Moyen) : Achat de V-Bucks (Fortnite)
Dans Fortnite, on peut acheter des V-Bucks avec les packs suivants : `{500, 1000, 2800, 5000, 13500}` V-Bucks.
Tu veux acheter exactement **8000 V-Bucks** en utilisant le moins de packs possible.
1. Appliquer l'algorithme glouton **à la main** pour obtenir 8000 V-Bucks. Combien de packs sont nécessaires ?
2. Existe-t-il une meilleure solution ?
3. Ce système est-il canonique (le glouton donne-t-il toujours l'optimal) ?
<details>
<summary><strong>Voir la correction</strong></summary>
**Question 1 : Algorithme glouton**
- On prend 5000 (le plus grand ≤ 8000) : reste 3000
- On prend 2800 : reste 200
- 200 < 500, on ne peut plus rien prendre !
L'algorithme glouton **échoue** à donner exactement 8000.
**Question 2 : Meilleure solution**
- 8000 = 5000 + 1000 + 1000 + 1000 = **4 packs**
- Ou : 8000 = 2800 + 2800 + 1000 + 1000 + 500 - 100... non ça ne marche pas non plus facilement.
En fait, 8000 = 5000 + 1000 × 3 = **4 packs** est la solution.
**Question 3 :**
Non, ce système n'est pas canonique. L'algorithme glouton ne fonctionne pas toujours car les valeurs ne sont pas des multiples les unes des autres.
</details>
---
## Exercice 2 (Facile) : Playlist Spotify optimale
Tu prépares une playlist pour un trajet de **60 minutes**. Tu veux y mettre le maximum de sons parmi tes favoris :
| Titre | Artiste | Durée (min) |
|-------|---------|-------------|
| Alibi | Sevdaliza | 4 |
| La Kiffance | Naps | 3 |
| Bande organisée | Jul & SCH | 6 |
| Mood | 24kGoldn | 2 |
| Fever | Dua Lipa | 3 |
| Blinding Lights | The Weeknd | 3 |
| Peaches | Justin Bieber | 3 |
| Heat Waves | Glass Animals | 4 |
| Iko Iko | Justin Wellington | 3 |
| Astronaut in the Ocean | Masked Wolf | 2 |
**Objectif** : Maximiser le nombre de titres dans la playlist sans dépasser 60 minutes.
1. Quelle stratégie gloutonne proposez-vous ?
2. Appliquer cette stratégie. Combien de titres obtenez-vous ?
3. Quelle est la durée totale de la playlist ?
<details>
<summary><strong>Voir la correction</strong></summary>
**Question 1 : Stratégie gloutonne**
Pour maximiser le **nombre** de titres, on prend les titres **les plus courts en premier**.
**Question 2 : Application**
Tri par durée croissante :
- Mood (2 min) → total = 2
- Astronaut in the Ocean (2 min) → total = 4
- La Kiffance (3 min) → total = 7
- Fever (3 min) → total = 10
- Blinding Lights (3 min) → total = 13
- Peaches (3 min) → total = 16
- Iko Iko (3 min) → total = 19
- Alibi (4 min) → total = 23
- Heat Waves (4 min) → total = 27
- Bande organisée (6 min) → total = 33
**Tous les 10 titres** rentrent dans 60 minutes !
**Question 3 :**
Durée totale : **33 minutes**
*Note : Dans ce cas, la contrainte de 60 min n'était pas limitante. On aurait pu ajouter d'autres titres.*
</details>
---
## Exercice 3 (Moyen) : Inventaire Minecraft
Tu joues à Minecraft et ton inventaire peut contenir **64 objets** maximum. Tu veux maximiser la valeur totale des objets pour le commerce avec les villageois.
| Objet | Quantité dispo | Valeur (émeraudes) | Poids (slots) |
|-------|----------------|-------------------|---------------|
| Diamant | 10 | 8 | 1 |
| Lingot d'or | 20 | 3 | 1 |
| Fer | 50 | 1 | 1 |
| Livre enchanté | 5 | 15 | 1 |
| Émeraude | 30 | 1 | 1 |
*Chaque objet prend 1 slot, mais tu ne peux pas dépasser 64 slots au total.*
1. Calculer le ratio valeur/slot pour chaque objet.
2. Appliquer l'algorithme glouton (meilleur ratio d'abord).
3. Quelle est la valeur totale obtenue ?
<details>
<summary><strong>Voir la correction</strong></summary>
**Question 1 : Ratios valeur/slot**
| Objet | Valeur | Ratio |
|-------|--------|-------|
| Livre enchanté | 15 | 15.0 |
| Diamant | 8 | 8.0 |
| Lingot d'or | 3 | 3.0 |
| Émeraude | 1 | 1.0 |
| Fer | 1 | 1.0 |
**Question 2 : Algorithme glouton**
Tri par ratio décroissant, on prend dans l'ordre :
- Livre enchanté : 5 objets → slots = 5, valeur = 75
- Diamant : 10 objets → slots = 15, valeur = 75 + 80 = 155
- Lingot d'or : 20 objets → slots = 35, valeur = 155 + 60 = 215
- Émeraude : 29 objets (64-35=29) → slots = 64, valeur = 215 + 29 = 244
**Question 3 : Valeur totale**
**244 émeraudes** avec 64 slots utilisés.
</details>
---
## Exercice 4 (Difficile) : Planning de stream Twitch
Tu es streamer et tu dois planifier tes lives pour demain. Plusieurs marques te proposent des partenariats avec des créneaux imposés :
| Sponsor | Début | Fin | Rémunération |
|---------|-------|-----|--------------|
| Red Bull | 14h | 17h | 200€ |
| Logitech | 15h | 18h | 180€ |
| Samsung | 17h | 19h | 150€ |
| Razer | 18h | 20h | 120€ |
| Discord | 19h | 21h | 100€ |
| NordVPN | 20h | 22h | 90€ |
**Objectif** : Maximiser le nombre de partenariats (pas de chevauchement possible).
1. Quelle stratégie gloutonne permet de maximiser le **nombre** de streams ?
2. Appliquer cette stratégie. Quels sponsors sélectionnez-vous ?
3. Implémenter l'algorithme en Python.
<details>
<summary><strong>Voir la correction</strong></summary>
**Question 1 : Stratégie**
Pour maximiser le nombre d'activités, on trie par **heure de fin croissante** et on prend chaque activité compatible.
**Question 2 : Application**
Tri par heure de fin : Red Bull (17h), Logitech (18h), Samsung (19h), Razer (20h), Discord (21h), NordVPN (22h)
- Red Bull (14h-17h) : OK
- Logitech (15h-18h) : chevauche Red Bull, refusé
- Samsung (17h-19h) : commence à 17h, Red Bull finit à 17h, OK
- Razer (18h-20h) : chevauche Samsung, refusé
- Discord (19h-21h) : commence à 19h, Samsung finit à 19h, OK
- NordVPN (20h-22h) : chevauche Discord, refusé
**Sponsors sélectionnés : Red Bull, Samsung, Discord** = 3 streams
Rémunération totale : 200 + 150 + 100 = **450€**
**Question 3 : Code Python**
```python
def planning_stream(sponsors):
"""
sponsors : liste de tuples (nom, debut, fin, remuneration)
Retourne la liste des sponsors sélectionnés
"""
# Trier par heure de fin croissante
sponsors_tries = sorted(sponsors, key=lambda x: x[2])
selection = []
derniere_fin = 0
for nom, debut, fin, remuneration in sponsors_tries:
if debut >= derniere_fin:
selection.append((nom, debut, fin, remuneration))
derniere_fin = fin
return selection
# Exemple d'utilisation
sponsors = [
('Red Bull', 14, 17, 200),
('Logitech', 15, 18, 180),
('Samsung', 17, 19, 150),
('Razer', 18, 20, 120),
('Discord', 19, 21, 100),
('NordVPN', 20, 22, 90)
]
planning = planning_stream(sponsors)
total = sum(s[3] for s in planning)
print("Sponsors sélectionnés :")
for nom, debut, fin, remuneration in planning:
print(" ", nom, ":", debut, "h -", fin, "h (", remuneration, "€)")
print("Rémunération totale :", total, "€")
```
</details>
---
## Exercice 5 (Difficile) : Draft d'Arène (jeu de cartes)
Dans le mode **Arène** d'un jeu de cartes, on ne joue pas avec sa collection : on **drafte** son deck. On t'ouvre un booster de 3 cartes, tu en gardes **une seule**, et on passe au booster suivant. **Une carte écartée est perdue pour toujours : on ne revient jamais en arrière.**
Chaque carte a une **puissance** (plus c'est haut, mieux c'est) et un **coût en mana** (le prix à payer pour la poser sur le plateau).
> **Règle de jouabilité.** Un deck de 5 cartes n'est jouable que s'il contient **au plus 2 cartes coûtant 5 manas ou plus**. Sinon, tu n'as rien à jouer pendant tes premiers tours, tu perds la partie avant d'avoir pu poser tes grosses cartes : le deck est déclaré **injouable**.
**Objectif** : obtenir le deck jouable de puissance totale maximale.
**Booster 1**
| Carte | Puissance | Coût |
|-------|-----------|------|
| Moineau vif | 2 | 1 |
| Druide chétif | 4 | 3 |
| Gardien de pierre | 5 | 5 |
**Booster 2**
| Carte | Puissance | Coût |
|-------|-----------|------|
| Acolyte du givre | 3 | 2 |
| Chevaucheur de loup | 4 | 3 |
| Abomination | 6 | 6 |
**Booster 3**
| Carte | Puissance | Coût |
|-------|-----------|------|
| Voleuse de poches | 2 | 1 |
| Sentinelle elfe | 4 | 4 |
| Ver de foudre | 8 | 7 |
**Booster 4**
| Carte | Puissance | Coût |
|-------|-----------|------|
| Mage novice | 1 | 1 |
| Alchimiste fou | 3 | 2 |
| Dragon de givre | 9 | 8 |
**Booster 5**
| Carte | Puissance | Coût |
|-------|-----------|------|
| Bouffon du roi | 3 | 2 |
| Capitaine pirate | 5 | 4 |
| Kraken des profondeurs | 6 | 6 |
1. Applique la stratégie gloutonne la plus naturelle : **à chaque booster, prendre la carte la plus puissante**. Quel deck obtiens-tu ? Quelle est sa puissance totale ? Est-il jouable ?
2. Corrige la stratégie pour qu'elle respecte la règle : **à chaque booster, prendre la carte la plus puissante parmi celles qu'on a encore le droit de prendre**. Quel deck obtiens-tu ? Quelle est sa puissance ?
3. Trouve un deck jouable **strictement meilleur** que celui de la question 2. Où l'algorithme glouton s'est-il fait piéger ?
4. Le problème vient d'un choix fait au booster 1. Pourquoi l'algorithme glouton ne peut-il pas le corriger une fois arrivé au booster 4 ?
<details>
<summary><strong>Voir la correction</strong></summary>
**Question 1 : glouton naïf**
| Booster | Carte prise | Puissance | Coût |
|---------|-------------|-----------|------|
| 1 | Gardien de pierre | 5 | 5 |
| 2 | Abomination | 6 | 6 |
| 3 | Ver de foudre | 8 | 7 |
| 4 | Dragon de givre | 9 | 8 |
| 5 | Kraken des profondeurs | 6 | 6 |
Puissance totale : **34**... mais le deck contient **5 cartes à 5 manas ou plus**, alors que la limite est de 2.
Le deck est **injouable**. L'algorithme glouton n'a pas donné un résultat « un peu moins bon » : il a donné un résultat **inutilisable**. En ne regardant que la puissance, il a complètement ignoré la contrainte de coût.
**Question 2 : glouton contraint**
On compte au fur et à mesure les cartes chères déjà prises.
| Booster | Cartes autorisées | Carte prise | Puissance | Cartes chères |
|---------|-------------------|-------------|-----------|---------------|
| 1 | toutes (0 chère prise) | Gardien de pierre (5) | 5 | 1 / 2 |
| 2 | toutes (1 chère prise) | Abomination (6) | 6 | 2 / 2 |
| 3 | quota plein → seulement les cartes < 5 manas | Sentinelle elfe (4) | 4 | 2 / 2 |
| 4 | quota plein | Alchimiste fou (3) | 3 | 2 / 2 |
| 5 | quota plein | Capitaine pirate (5) | 5 | 2 / 2 |
Deck jouable, puissance totale : **23**.
**Question 3 : mieux**
Deck optimal : Druide chétif (4) + Chevaucheur de loup (4) + **Ver de foudre (8)** + **Dragon de givre (9)** + Capitaine pirate (5) = **30**.
Il ne contient bien que 2 cartes chères (Ver de foudre et Dragon de givre), il est donc jouable.
**Le piège** : le glouton a dépensé ses 2 places de cartes chères dès les boosters 1 et 2, pour des gains ridicules.
- Au booster 1, prendre le Gardien de pierre (5) au lieu du Druide chétif (4) rapporte **+1**.
- Au booster 2, prendre l'Abomination (6) au lieu du Chevaucheur de loup (4) rapporte **+2**.
- Mais au booster 3, le Ver de foudre (8) au lieu de la Sentinelle elfe (4) rapportait **+4**.
- Et au booster 4, le Dragon de givre (9) au lieu de l'Alchimiste fou (3) rapportait **+6**.
Le glouton a payé +1 et +2 des places qui valaient +4 et +6. Il a fait deux fois le meilleur choix **du moment**, et c'est précisément ce qui l'a ruiné.
**Question 4 :**
Parce que c'est la définition même d'un algorithme glouton : **il ne revient jamais sur un choix déjà fait**. Arrivé au booster 4, il « voit » bien que le Dragon de givre serait excellent, mais son quota est plein et le Gardien de pierre est déjà dans le deck — il ne peut plus l'échanger.
Ici la règle du jeu et la règle de l'algorithme coïncident : dans un draft, une carte écartée est réellement perdue.
Plus profondément, au booster 1 l'algorithme **n'avait aucun moyen de savoir** qu'un Dragon de givre l'attendait au booster 4 : il décide avec une vision purement locale. C'est pour cela qu'un algorithme glouton est une **heuristique** — il donne vite une solution correcte, pas forcément la meilleure.
</details>
---
## Exercice 6 (Moyen) : Réflexion
1. Dans l'exercice 4, on a maximisé le **nombre** de streams. Si on voulait maximiser la **rémunération totale**, l'algorithme glouton donnerait-il le même résultat ?
2. Parmi ces situations, lesquelles peuvent être résolues de manière optimale par un algorithme glouton ?
- Choisir les meilleurs joueurs pour une équipe FIFA (budget limité)
- Organiser l'ordre de visionnage de films sur Netflix (minimiser le temps total)
- Rendre la monnaie avec des pièces européennes
- Trouver le chemin le plus court dans Google Maps
<details>
<summary><strong>Voir la correction</strong></summary>
**Question 1 :**
Non ! Pour maximiser la rémunération, l'algorithme glouton pourrait donner un résultat différent.
Avec notre solution (Red Bull + Samsung + Discord) : 450€
Si on avait pris Red Bull (200€) + Razer (120€) + NordVPN (90€) : 410€ (moins bien)
Mais que se passe-t-il si on prend Logitech (180€) + Discord (100€) = 280€ ? C'est pire.
En fait, pour ce problème précis, la solution gloutonne par heure de fin est bonne, mais **maximiser la rémunération** est un problème différent (problème du sac à dos déguisé) qui ne se résout pas toujours de manière optimale avec un glouton.
**Question 2 :**
| Situation | Optimal avec glouton ? |
|-----------|------------------------|
| Équipe FIFA (budget) | Non (c'est un sac à dos) |
| Ordre films Netflix | Ça dépend du critère... |
| Monnaie européenne | Oui (système canonique) |
| Google Maps | Non (Dijkstra n'est pas vraiment glouton au sens strict, mais utilise une approche similaire) |
</details>
----------
Auteur : Florian Mathieu
Licence CC BY-SA
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-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-sa/4.0/">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>