From 5cdf32fdae8339b55af04a45f14ce80a480afedb Mon Sep 17 00:00:00 2001 From: rabot Date: Wed, 21 Oct 2026 11:15:43 +0200 Subject: [PATCH] Optimiser F8 avec un tableau de programmation dynamique --- COMPTE_RENDU.md | 17 +++++++++++++++++ banque.c | 18 +++++++++++++----- tests/test_banque.c | 18 ++++++++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/COMPTE_RENDU.md b/COMPTE_RENDU.md index 6a9163c..2f1ad9e 100644 --- a/COMPTE_RENDU.md +++ b/COMPTE_RENDU.md @@ -331,3 +331,20 @@ paires sur les **97 655 tableaux** de longueur 1 à 7 à montants dans `[-2, 2]`, ainsi que sur une entrée vide. Ils vérifient aussi que les transactions d'origine restent inchangées, notamment en présence de doublons et de plusieurs zéros. + +### F8 — Programmation dynamique pour le rendu de monnaie + +`facons[s]` contient le nombre de façons de rendre `s` avec les pièces déjà +traitées. Il vaut initialement 1 pour la somme nulle et 0 ailleurs. Pour +chaque pièce, les sommes sont parcourues dans l'ordre croissant et l'on +ajoute `facons[s - piece]` à `facons[s]`. Ce sens permet la réutilisation +d'une pièce ; la boucle des pièces à l'extérieur compte des combinaisons, +sans distinguer l'ordre des pièces. + +Chaque état est calculé une seule fois par type de pièce : **`O(S × k)`** +pour `k ≥ 1` (et `O(S × k + S)` en incluant l'initialisation si `k = 0`), +avec **`O(S)`** de mémoire. La récursion et ses sous-problèmes répétés +disparaissent. F8 passe de **M = 4 à M = 5** : l'amélioration temporelle +n'implique pas une baisse de M. Les tests comparent les résultats à la +récursion initiale pour les sommes de -2 à 40 et de 0 à 8 types de pièces, +y compris la somme nulle et l'absence de pièces. diff --git a/banque.c b/banque.c index 0a23675..7b71498 100644 --- a/banque.c +++ b/banque.c @@ -242,12 +242,20 @@ static const int PIECES[] = {1, 2, 5, 10, 20, 50, 100, 200}; long nb_facons_rendre(int somme, int nb_pieces) { - if (somme == 0) - return 1; - if (somme < 0 || nb_pieces == 0) + if (somme < 0) return 0; - return nb_facons_rendre(somme - PIECES[nb_pieces - 1], nb_pieces) + - nb_facons_rendre(somme, nb_pieces - 1); + long *facons = calloc((size_t)somme + 1, sizeof(*facons)); + if (facons == NULL) { + perror("Allocation du tableau de rendu de monnaie"); + exit(EXIT_FAILURE); + } + facons[0] = 1; + for (int p = 0; p < nb_pieces; p++) + for (int s = PIECES[p]; s <= somme; s++) + facons[s] += facons[s - PIECES[p]]; + long resultat = facons[somme]; + free(facons); + return resultat; } /* F9 : catégorie d'une transaction (pour les statistiques) */ diff --git a/tests/test_banque.c b/tests/test_banque.c index e5f7db7..110738e 100644 --- a/tests/test_banque.c +++ b/tests/test_banque.c @@ -207,6 +207,23 @@ static void tester_paires(void) } } +static long monnaie_reference(int somme, int nb_pieces) +{ + if (somme == 0) + return 1; + if (somme < 0 || nb_pieces == 0) + return 0; + return monnaie_reference(somme - PIECES[nb_pieces - 1], nb_pieces) + + monnaie_reference(somme, nb_pieces - 1); +} + +static void tester_monnaie(void) +{ + for (int s = -2; s <= 40; s++) + for (int k = 0; k <= NB_PIECES; k++) + assert(nb_facons_rendre(s, k) == monnaie_reference(s, k)); +} + int main(void) { tester_tri(); @@ -216,6 +233,7 @@ int main(void) tester_periodes(); tester_recherches(); tester_paires(); + tester_monnaie(); puts("Tests banque : OK"); return 0; }