modifications des tp, exercices, ajouts d'indications en JS, d'exemples en gloutons, 3 semaines de boulot enfin voilà
This commit is contained in:
@@ -22,16 +22,16 @@ Selon le problème on utilise une méthode pour résoudre ce dernier. Il peut ex
|
||||
|
||||
À un problème d'optimisation, on associe une fonction objective.
|
||||
|
||||
Prenons un exemple simple : la liste des 23 joueurs selectionnés pour la coupe du monde :
|
||||
Prenons un exemple simple : la liste des 23 joueurs sélectionnés pour la coupe du monde :
|
||||
|
||||
```
|
||||
Didier Desvilles est bien embêté : il doit choisir 23 joueurs pour aller jouer une compétition.
|
||||
Dans cette optique, il décide d'utiliser une méthode simple: choisir le meilleur joueur possible pour chaque poste, puis le deuxième meilleur comme remplaçant.
|
||||
|
||||
Peu importe si les joueurs selectionnés ne s'entendent pas forcément très bien, comme Olivier Gibrun et Karim Benzemb, l'important c'est de faire le meilleur choix à chaque étape.
|
||||
Peu importe si les joueurs sélectionnés ne s'entendent pas forcément très bien, comme Olivier Gibrun et Karim Benzemb, l'important c'est de faire le meilleur choix à chaque étape.
|
||||
```
|
||||
|
||||
Un algorithme glouton ne renvoie pas obligatoirement un résultat optimal, dans ce cas la, on parle ***d'heuristique.*** Il renverra un résultat optimal pour chacun des sous-problèmes.
|
||||
Un algorithme glouton ne renvoie pas obligatoirement un résultat optimal, dans ce cas-là, on parle ***d'heuristique.*** Il renverra un résultat optimal pour chacun des sous-problèmes.
|
||||
|
||||
Un algorithme glouton ne revient pas sur un sous-problème déjà traité.
|
||||
|
||||
@@ -41,23 +41,19 @@ Un algorithme glouton ne revient pas sur un sous-problème déjà traité.
|
||||
|
||||
> Le problème du rendu de monnaie s'énonce de la façon suivante : étant donné un système de monnaie (pièces et billets), comment rendre une somme donnée de façon optimale, c'est-à-dire avec le nombre minimal de pièces et billets ?
|
||||
|
||||
On veut programmer une caisse automatique qui rend de façon optimal la monnaie (le moins de pièces/billets) :
|
||||
On veut programmer une caisse automatique qui rend de façon optimale la monnaie (le moins de pièces/billets) :
|
||||
|
||||
#### **Des exemples**
|
||||
|
||||
```
|
||||
Système de monnaie : ```{1, 2, 5, 10}```
|
||||
**Exemple 1 :**
|
||||
- Système de monnaie : `{1, 2, 5, 10}`
|
||||
- Recherché : `14`
|
||||
- Résultat optimal : `10 + 2 + 2` (3 pièces)
|
||||
|
||||
Recherché : ```14```
|
||||
|
||||
Résultat optimal : 10 + 2 + 2
|
||||
```
|
||||
|
||||
Système de monnaie : ```{1, 2, 5, 7, 10}```
|
||||
|
||||
Recherché : ```14```
|
||||
|
||||
Résultat optimal : 7 + 7
|
||||
**Exemple 2 :**
|
||||
- Système de monnaie : `{1, 2, 5, 7, 10}`
|
||||
- Recherché : `14`
|
||||
- Résultat optimal : `7 + 7` (2 pièces)
|
||||
|
||||
#### **Algorithme**
|
||||
|
||||
@@ -86,9 +82,9 @@ print(rendu_monnaie(systeme_2, 14)) # Devrait afficher [10, 2, 2] qui est non o
|
||||
|
||||
```
|
||||
|
||||
Force brute avec le ```system_2``` pour ```14```:
|
||||
Force brute avec le ```systeme_2``` pour ```14```:
|
||||
|
||||
On cherche **toute** les solutions possibles :
|
||||
On cherche **toutes** les solutions possibles :
|
||||
- \[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\]
|
||||
- \[2, 2, 2, 2, 2, 2, 2\]
|
||||
- \[5, 5, 2, 2\]
|
||||
@@ -97,7 +93,7 @@ On cherche **toute** les solutions possibles :
|
||||
- \[10, 2, 2]
|
||||
- ...
|
||||
|
||||
On parcours la liste des solutions pour garder la solution la plus optimal (la plus courte) : **\[7, 7\]**.
|
||||
On parcourt la liste des solutions pour garder la solution la plus optimale (la plus courte) : **\[7, 7\]**.
|
||||
|
||||
### Exemples de problèmes que l'on peut résoudre par algorithme glouton
|
||||
|
||||
@@ -108,20 +104,131 @@ On parcours la liste des solutions pour garder la solution la plus optimal (la p
|
||||
|
||||
### **Sac à dos**
|
||||
|
||||
2 systemes : \[(valeur, poids)\]
|
||||
> Un voleur entre dans une maison avec un sac à dos pouvant contenir un poids maximum. Il trouve plusieurs objets, chacun ayant une valeur et un poids. Quels objets doit-il prendre pour maximiser la valeur totale sans dépasser la capacité du sac ?
|
||||
|
||||
- ```[(22, 11), (5, 5), (1, 1)]``` ;
|
||||
- ```[(12, 11), (10, 5), (10, 4), (1, 1)]```.
|
||||
#### Exemple
|
||||
|
||||
Pour un poids max de ```12```.
|
||||
Objets disponibles (valeur, poids) : `[(60, 10), (100, 20), (120, 30)]`
|
||||
|
||||
Plusieurs stratégies : **valeur/poids**, **le + de valeur** ou **le poids le plus gros**.
|
||||
Capacité du sac : `50 kg`
|
||||
|
||||
La fonction (et donc le résultat optimal) dépendra de la stratégie choisie.
|
||||
#### Stratégies gloutonnes possibles
|
||||
|
||||
1. **Prendre l'objet de plus grande valeur** en premier
|
||||
2. **Prendre l'objet le plus léger** en premier
|
||||
3. **Prendre l'objet avec le meilleur ratio valeur/poids** en premier (souvent la meilleure stratégie)
|
||||
|
||||
#### Algorithme (stratégie ratio valeur/poids)
|
||||
|
||||
```python
|
||||
def sac_a_dos_glouton(objets, capacite):
|
||||
"""
|
||||
objets : liste de tuples (valeur, poids)
|
||||
capacite : poids maximum du sac
|
||||
"""
|
||||
# Calculer le ratio valeur/poids et trier par ratio décroissant
|
||||
objets_avec_ratio = [(v, p, v/p) for v, p in objets]
|
||||
objets_tries = sorted(objets_avec_ratio, key=lambda x: x[2], reverse=True)
|
||||
|
||||
poids_total = 0
|
||||
valeur_totale = 0
|
||||
sac = []
|
||||
|
||||
for valeur, poids, ratio in objets_tries:
|
||||
if poids_total + poids <= capacite:
|
||||
sac.append((valeur, poids))
|
||||
poids_total += poids
|
||||
valeur_totale += valeur
|
||||
|
||||
return sac, valeur_totale, poids_total
|
||||
|
||||
# Exemple d'utilisation
|
||||
objets = [(60, 10), (100, 20), (120, 30)]
|
||||
capacite = 50
|
||||
|
||||
sac, valeur, poids = sac_a_dos_glouton(objets, capacite)
|
||||
print(f"Objets pris : {sac}")
|
||||
print(f"Valeur totale : {valeur}, Poids total : {poids}")
|
||||
# Résultat : [(60, 10), (100, 20)] avec valeur=160 et poids=30
|
||||
# Note : ce n'est pas optimal ! L'optimal serait [(100, 20), (120, 30)] = 220
|
||||
```
|
||||
|
||||
> **Attention** : L'algorithme glouton ne donne pas toujours la solution optimale pour le problème du sac à dos !
|
||||
|
||||
---------
|
||||
|
||||
### **Voyageur de commerce**
|
||||
|
||||
Le problème du **voyageur de commerce**, est un problème d'optimisation qui, étant donné une liste de villes, et des distances entre toutes les paires de villes, détermine un plus court circuit qui visite chaque ville une et une seule fois.
|
||||
> Un voyageur de commerce doit visiter plusieurs villes exactement une fois, puis revenir à son point de départ. Quel est le chemin le plus court ?
|
||||
|
||||
#### Exemple
|
||||
|
||||
Imaginons 4 villes : A, B, C, D avec les distances suivantes :
|
||||
|
||||
| De/Vers | A | B | C | D |
|
||||
|---------|---|---|---|---|
|
||||
| A | - | 10 | 15 | 20 |
|
||||
| B | 10 | - | 35 | 25 |
|
||||
| C | 15 | 35 | - | 30 |
|
||||
| D | 20 | 25 | 30 | - |
|
||||
|
||||
#### Stratégie gloutonne : "Plus proche voisin"
|
||||
|
||||
À chaque étape, on se déplace vers la ville non visitée la plus proche.
|
||||
|
||||
```python
|
||||
def voyageur_commerce_glouton(distances, depart=0):
|
||||
"""
|
||||
distances : matrice des distances entre villes
|
||||
depart : indice de la ville de départ
|
||||
"""
|
||||
n = len(distances)
|
||||
visitees = [False] * n
|
||||
chemin = [depart]
|
||||
visitees[depart] = True
|
||||
distance_totale = 0
|
||||
|
||||
ville_actuelle = depart
|
||||
|
||||
for _ in range(n - 1):
|
||||
# Trouver la ville non visitée la plus proche
|
||||
plus_proche = None
|
||||
dist_min = float('inf')
|
||||
|
||||
for ville in range(n):
|
||||
if not visitees[ville] and distances[ville_actuelle][ville] < dist_min:
|
||||
dist_min = distances[ville_actuelle][ville]
|
||||
plus_proche = ville
|
||||
|
||||
# Se déplacer vers cette ville
|
||||
chemin.append(plus_proche)
|
||||
visitees[plus_proche] = True
|
||||
distance_totale += dist_min
|
||||
ville_actuelle = plus_proche
|
||||
|
||||
# Retour au point de départ
|
||||
distance_totale += distances[ville_actuelle][depart]
|
||||
chemin.append(depart)
|
||||
|
||||
return chemin, distance_totale
|
||||
|
||||
# Exemple d'utilisation
|
||||
distances = [
|
||||
[0, 10, 15, 20], # Distances depuis A
|
||||
[10, 0, 35, 25], # Distances depuis B
|
||||
[15, 35, 0, 30], # Distances depuis C
|
||||
[20, 25, 30, 0] # Distances depuis D
|
||||
]
|
||||
|
||||
chemin, distance = voyageur_commerce_glouton(distances, depart=0)
|
||||
villes = ['A', 'B', 'C', 'D']
|
||||
chemin_noms = [villes[i] for i in chemin]
|
||||
print(f"Chemin : {' -> '.join(chemin_noms)}")
|
||||
print(f"Distance totale : {distance}")
|
||||
# Résultat : A -> B -> D -> C -> A avec distance = 80
|
||||
```
|
||||
|
||||
> **Note** : Le problème du voyageur de commerce est un problème **NP-difficile**. Pour un grand nombre de villes, trouver la solution optimale prend un temps exponentiel. L'approche gloutonne donne une solution acceptable rapidement, mais rarement optimale.
|
||||
|
||||
--------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user