Optimiser F8 avec un tableau de programmation dynamique

This commit is contained in:
rabot
2026-10-21 11:15:43 +02:00
parent 02fcd4b443
commit 5cdf32fdae
3 changed files with 48 additions and 5 deletions
+17
View File
@@ -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 `[-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 transactions d'origine restent inchangées, notamment en présence de
doublons et de plusieurs zéros. 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.
+13 -5
View File
@@ -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) long nb_facons_rendre(int somme, int nb_pieces)
{ {
if (somme == 0) if (somme < 0)
return 1;
if (somme < 0 || nb_pieces == 0)
return 0; return 0;
return nb_facons_rendre(somme - PIECES[nb_pieces - 1], nb_pieces) + long *facons = calloc((size_t)somme + 1, sizeof(*facons));
nb_facons_rendre(somme, nb_pieces - 1); 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) */ /* F9 : catégorie d'une transaction (pour les statistiques) */
+18
View File
@@ -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) int main(void)
{ {
tester_tri(); tester_tri();
@@ -216,6 +233,7 @@ int main(void)
tester_periodes(); tester_periodes();
tester_recherches(); tester_recherches();
tester_paires(); tester_paires();
tester_monnaie();
puts("Tests banque : OK"); puts("Tests banque : OK");
return 0; return 0;
} }