Particularité : Nous pouvons prendre des fractions d'articles (contrairement au sac à dos 0/1). Cela rend le problème adapté à une approche gloutonne.
Exemples
Articles = [(60, 10), (100, 20), (100, 60), (40, 20)] Capacité C = 50
200.0
Articles = [(120, 30), (100, 20), (60, 10)] Capacité C = 50
280.0
Articles = [(60, 10), (100, 20), (120, 30)] Capacité C = 50
240.0
Articles = [(500, 30)] Capacité C = 20
333.3333333333333
Une solution naïve consisterait à essayer tous les sous-ensembles possibles avec des fractions différentes, mais cela prendrait trop de temps (complexité exponentielle).
Une solution efficace consiste à utiliser l'approche gloutonne. L'idée de l'approche gloutonne est de calculer le rapport valeur/poids pour chaque article et de trier les articles sur la base de ce rapport (du plus élevé au plus bas). Ensuite, on prend l'élément avec le rapport le plus élevé et on l'ajoute entièrement jusqu'à ce que nous ne puissions plus ajouter l'élément suivant dans son intégralité. À la fin, on ajoute une fraction du dernier article possible.
1. Calculer le rapport valeur/poids pour chaque article.
2. Trier les articles par ordre décroissant de ce rapport.
3. Initialiser la valeur totale à 0.
4. Pour chaque article dans l'ordre trié :
a. Si l'article entier peut tenir dans la capacité restante :
Ajouter l'article entier à la solution
Réduire la capacité du poids de l'article
Ajouter sa valeur totale au résultat
b. Sinon :
Ajouter une fraction de l'article (capacité restante / poids de l'article)
Ajouter la valeur fractionnaire au résultat
Terminer (capacité atteinte)
5. Retourner la valeur totale maximale.#include <stdio.h>
#include <stdlib.h>
// Structure pour représenter un article
typedef struct {
int valeur;
int poids;
float rapport;
} Article;
// Fonction de comparaison pour le tri décroissant selon le rapport
int comparer(const void* a, const void* b) {
Article* articleA = (Article*)a;
Article* articleB = (Article*)b;
if (articleA->rapport < articleB->rapport)
return 1;
else if (articleA->rapport > articleB->rapport)
return -1;
else
return 0;
}
float sacADos(Article articles[], int n, int capacite) {
// Calculer les rapports valeur/poids
for (int i = 0; i < n; i++) {
articles[i].rapport = (float)articles[i].valeur / articles[i].poids;
}
// Trier les articles par rapport décroissant
qsort(articles, n, sizeof(Article), comparer);
float valeurTotale = 0.0;
int poidsRestant = capacite;
printf("Articles sélectionnés (dans l'ordre) :\n");
for (int i = 0; i < n; i++) {
if (articles[i].poids <= poidsRestant) {
// Prendre l'article entier
printf(" - Article entier (valeur=%d, poids=%d, rapport=%.2f)\n",
articles[i].valeur, articles[i].poids, articles[i].rapport);
poidsRestant -= articles[i].poids;
valeurTotale += articles[i].valeur;
} else {
// Prendre une fraction de l'article
float fraction = (float)poidsRestant / articles[i].poids;
printf(" - Fraction de l'article (%.2f × %d = %.2f, rapport=%.2f)\n",
fraction, articles[i].valeur, fraction * articles[i].valeur, articles[i].rapport);
valeurTotale += articles[i].valeur * fraction;
break; // Sac plein
}
}
return valeurTotale;
}
int main() {
// Exemple 1
Article articles1[] = {
{60, 10, 0},
{100, 20, 0},
{100, 60, 0},
{40, 20, 0}
};
int n1 = sizeof(articles1) / sizeof(articles1[0]);
int capacite1 = 50;
printf("=== Exemple 1 ===\n");
printf("Articles : (60,10), (100,20), (100,60), (40,20)\n");
printf("Capacité : %d\n\n", capacite1);
float resultat1 = sacADos(articles1, n1, capacite1);
printf("\nValeur maximale dans le sac à dos = %.2f\n\n", resultat1);
// Exemple 2
Article articles2[] = {
{60, 10, 0},
{100, 20, 0},
{120, 30, 0}
};
int n2 = sizeof(articles2) / sizeof(articles2[0]);
int capacite2 = 50;
printf("=== Exemple 2 ===\n");
printf("Articles : (60,10), (100,20), (120,30)\n");
printf("Capacité : %d\n\n", capacite2);
float resultat2 = sacADos(articles2, n2, capacite2);
printf("\nValeur maximale dans le sac à dos = %.2f\n\n", resultat2);
// Exemple 3 (cas d'un seul article)
Article articles3[] = {
{500, 30, 0}
};
int n3 = sizeof(articles3) / sizeof(articles3[0]);
int capacite3 = 20;
printf("=== Exemple 3 ===\n");
printf("Articles : (500,30)\n");
printf("Capacité : %d\n\n", capacite3);
float resultat3 = sacADos(articles3, n3, capacite3);
printf("\nValeur maximale dans le sac à dos = %.2f\n", resultat3);
return 0;
}def sac_dos_fractionnaire(articles, capacite):
"""
Résout le problème du sac à dos fractionnaire.
Paramètres:
articles: liste de tuples (valeur, poids)
capacite: capacité maximale du sac
Retourne:
float: valeur totale maximale
"""
# Créer une liste d'articles avec leur rapport valeur/poids
articles_avec_rapport = []
for i, (valeur, poids) in enumerate(articles):
rapport = valeur / poids
articles_avec_rapport.append((valeur, poids, rapport, i))
# Trier par rapport décroissant
articles_avec_rapport.sort(key=lambda x: x[2], reverse=True)
valeur_totale = 0.0
poids_restant = capacite
selection = [] # Pour stocker les articles sélectionnés
for valeur, poids, rapport, index in articles_avec_rapport:
if poids <= poids_restant:
# Prendre l'article entier
selection.append((index, 1.0, valeur, poids))
poids_restant -= poids
valeur_totale += valeur
else:
# Prendre une fraction de l'article
fraction = poids_restant / poids
selection.append((index, fraction, valeur * fraction, poids_restant))
valeur_totale += valeur * fraction
break # Sac plein
# Afficher les détails de la sélection
print("Articles sélectionnés :")
for index, fraction, valeur_contrib, poids_contrib in selection:
article_original = articles[index]
if fraction == 1.0:
print(f" - Article {index+1}: entier (valeur={article_original[0]}, poids={article_original[1]})")
else:
print(f" - Article {index+1}: fraction {fraction:.2f} (valeur={article_original[0]} × {fraction:.2f} = {valeur_contrib:.2f}, poids={poids_contrib:.1f})")
return valeur_totale
def afficher_resultat(articles, capacite):
"""Affiche le résultat de façon détaillée"""
print(f"Articles : {articles}")
print(f"Capacité : {capacite}")
print()
resultat = sac_dos_fractionnaire(articles, capacite)
print(f"\nValeur maximale dans le sac à dos = {resultat:.2f}")
print("-" * 50)
# Tester la fonction avec les exemples
print("=== Exemple 1 ===")
articles1 = [(60, 10), (100, 20), (100, 60), (40, 20)]
afficher_resultat(articles1, 50)
print("\n=== Exemple 2 ===")
articles2 = [(60, 10), (100, 20), (120, 30)]
afficher_resultat(articles2, 50)
print("\n=== Exemple 3 ===")
articles3 = [(500, 30)]
afficher_resultat(articles3, 20)
print("\n=== Exemple 4 (test interactif) ===")
# Test avec des valeurs personnalisées
articles_test = [(90, 20), (120, 30), (60, 10), (200, 40)]
capacite_test = 60
afficher_resultat(articles_test, capacite_test)=== Exemple 1 === Articles : [(60, 10), (100, 20), (100, 60), (40, 20)] Capacité : 50 Articles sélectionnés : - Article 1: entier (valeur=60, poids=10) - Article 2: entier (valeur=100, poids=20) - Article 4: entier (valeur=40, poids=20) Valeur maximale dans le sac à dos = 200.00 -------------------------------------------------- === Exemple 2 === Articles : [(60, 10), (100, 20), (120, 30)] Capacité : 50 Articles sélectionnés : - Article 1: entier (valeur=60, poids=10) - Article 2: entier (valeur=100, poids=20) - Article 3: fraction 0.67 (valeur=120 × 0.67 = 80.00, poids=20.0) Valeur maximale dans le sac à dos = 240.00 -------------------------------------------------- === Exemple 3 === Articles : [(500, 30)] Capacité : 20 Articles sélectionnés : - Article 1: fraction 0.67 (valeur=500 × 0.67 = 333.33, poids=20.0) Valeur maximale dans le sac à dos = 333.33 --------------------------------------------------
- Tri des articles : O(n log n) où n est le nombre d'articles
- Parcours des articles : O(n)
- Complexité totale : O(n log n)
- Complexité spatiale : O(n) pour stocker les articles avec leurs rapports
Comparaison des approches
| Approche | Complexité | Optimalité | Quand l'utiliser |
|---|---|---|---|
| Force brute | O(2ⁿ) | Optimale | Uniquement pour très petits ensembles (n ≤ 20) |
| Glouton (fractionnaire) | O(n log n) | Optimale pour version fractionnaire | Version fractionnaire du problème |
| Programmation dynamique | O(n × C) | Optimale pour version 0/1 | Version 0/1 avec capacité modérée |
- Tous les articles ont le même rapport : L'ordre de sélection n'a pas d'importance
- Capacité nulle : La valeur maximale est 0
- Articles avec poids nul : Peuvent être ajoutés sans limite (cas rare)
- Capacité très grande : Tous les articles peuvent être pris entièrement
- Sac à dos 0/1 : Chaque article est soit pris entièrement, soit pas du tout (pas de fraction)
- Sac à dos fractionnaire : Notre problème actuel
- Sac à dos avec contraintes multiples : Plusieurs dimensions (poids, volume, etc.)
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.