Files
cours/high-school/programmation_dynamique/bag/main.py
2025-09-26 11:16:23 +02:00

191 lines
5.8 KiB
Python

Videos = {
"Video 1": {"Durée": 114, "Taille": 4.57},
"Video 2": {"Durée": 32, "Taille": 0.63},
"Video 3": {"Durée": 20, "Taille": 1.65},
"Video 4": {"Durée": 4, "Taille": 0.085},
"Video 5": {"Durée": 18, "Taille": 2.15},
"Video 6": {"Durée": 80, "Taille": 2.71},
"Video 7": {"Durée": 5, "Taille": 0.32},
}
def dico_vers_liste(dico: dict) -> list:
"""
Conversion d'un dictionnaire en liste.
PARAM. :
- dico : DICT, dictionnaire à applatir
RESULT. :
- LIST, chaque élément de la liste est un tuple (cle, valeur) du dictionnaire.
PRECOND. :
- aucune
EFFET DE BORD :
- aucun
"""
return list(
dico.items() # j'ai remplacer le code de base qui contenait Videos a la place de dico dans le return
)
def entier_vers_binaire(n: int, taille: int) -> list:
"""
Conversion d'un entier en binaire sur une taille donnée.
PARAM. :
- n : INT, le nombre à convertir
- taille : INT, la taille (nb de bits) fixe de la représentation
RESULT. :
- LIST, la liste des bits de la représentation en binaire,
indexée par le poids
PRECONDITION :
- n < 2**taille : un entier >= 2**taille n'est pas représentable
dans la taille donnée
EFFET DE BORD :
- aucun
"""
assert 2**taille > n, "Taille de représentation trop petite"
bits = [0] * taille
for i in range(taille):
bits[i] = (n >> i) & 1
return bits
def ensemble_des_parties(ensemble: list):
"""
Construit l'itérable enumérant toutes les parties d'un ensemble.
PARAM. :
- ensemble : LIST, la liste des éléments de l'ensemble
RESULT. :
- ITERATOR, le générateur de toutes les parties de l'ensemble
PRECONDITION :
- aucune
EFFET DE BORD :
- aucun
"""
n = len(ensemble)
for mask in range(2**n):
partie = [ensemble[i] for i in range(n) if (mask >> i) & 1]
yield partie
def total_duree(partie):
return sum(elt[1]["Durée"] for elt in partie)
def total_taille(partie):
return sum(elt[1]["Taille"] for elt in partie)
def sac_a_dos_force_brute(videos, capacite):
meilleur = ([], 0, 0.0)
for partie in ensemble_des_parties(videos):
taille = total_taille(partie)
duree = total_duree(partie)
if taille <= capacite and duree > meilleur[1]:
meilleur = ([v[0] for v in partie], duree, taille)
return meilleur
# Glouton
def sac_a_dos_glouton(videos, capacite, cle):
tri = sorted(videos, key=cle, reverse=True)
sélection = []
totale_taille = 0.0
totale_duree = 0
for nom, info in tri:
if totale_taille + info["Taille"] <= capacite:
sélection.append(nom)
totale_taille += info["Taille"]
totale_duree += info["Durée"]
return sélection, totale_duree, totale_taille
"""def sac_a_dos_dynamique(videos, capacite):
precision = 100
capacite = int(capacite * precision)
liste = list(videos.items())
n = len(liste)
dp = [[0] * (capacite + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
nom, info = liste[i - 1]
duree = info["Durée"]
taille = int(info["taille"] * precision)
for cap in range(capacite + 1):
if taille <= cap:
dp[i][cap] = max(dp[i - 1][cap], duree + dp[i - 1][cap - taille])
else:
dp[i][cap] = dp[i - 1][cap]
cap = capacite
selection = []
for i in range(n, 0, -1):
if dp[i][cap] != dp[i - 1][cap]:
nom, info = liste[i - 1]
selection.append(nom)
cap -= int(info["taille"] * precision)
return selection[::-1]"""
def sac_a_dos_dyn(videos, cap):
videos = [(d, int(t * 100)) for (d, t) in videos]
capacite = int(cap * 100)
n = len(videos)
dp = [[0 for _ in range(capacite + 1)] for _ in range(n + 1)]
for k in range(1, n + 1):
duree_k, taille_k = videos[k - 1]
for w in range(capacite + 1):
if taille_k > w:
dp[k][w] = dp[k - 1][w]
else:
dp[k][w] = max(dp[k - 1][w], duree_k + dp[k - 1][w - taille_k])
w = capacite
choix = []
for k in range(n, 0, -1):
if dp[k][w] != dp[k - 1][w]:
choix.append(k - 1)
w -= videos[k - 1][1]
return dp[n][capacite], list(reversed(choix))
if __name__ == "__main__":
liste_videos = dico_vers_liste(Videos)
for video in liste_videos:
print(video)
opt_brut, dur_brut, taille_brut = sac_a_dos_force_brute(liste_videos, 5.0)
print("--- Force brute ---")
print(
f"Vidéos : {opt_brut}\nDurée : {dur_brut} min\nTaille : {taille_brut:.3f} Go\n"
)
h_duree = lambda x: x[1]["Durée"]
h_taille = lambda x: -x[1]["Taille"]
h_ratio = lambda x: x[1]["Durée"] / x[1]["Taille"]
selection_duree, dur_duree, taille_duree = sac_a_dos_glouton(
liste_videos, 5.0, h_duree
)
selection_taille, dur_taille, taille_taille = sac_a_dos_glouton(
liste_videos, 5.0, h_taille
)
selection_ratio, dur_ratio, taille_ratio = sac_a_dos_glouton(
liste_videos, 5.0, h_ratio
)
print("--- Glouton par durée décroissante ---")
print(
f"Vidéos : {selection_duree}\nDurée : {dur_duree} min\nTaille : {taille_duree:.3f} Go\n"
)
print("--- Glouton par taille croissante ---")
print(
f"Vidéos : {selection_taille}\nDurée : {dur_taille} min\nTaille : {taille_taille:.3f} Go\n"
)
print("--- Glouton par ratio durée/taille ---")
print(
f"Vidéos : {selection_ratio}\nDurée : {dur_ratio} min\nTaille : {taille_ratio:.3f} Go\n"
)
videos_mb = [
(nom, (info["Durée"], int(round(info["Taille"] * 1000))))
for nom, info in liste_videos
]
capacite_mb = 5000
n = len(videos_mb)
dp = [[0] * (capacite_mb + 1) for _ in range(n + 1)]