diff --git a/COMPTE_RENDU.md b/COMPTE_RENDU.md index ca01450..60db236 100644 --- a/COMPTE_RENDU.md +++ b/COMPTE_RENDU.md @@ -282,3 +282,20 @@ puis ajout de chaque montant dans `totaux[t[i].jour]`. Le coût passe de La complexité cyclomatique passe de **4 à 3**. Les tests comparent chaque solde à un calcul de référence, y compris aux bornes du tableau, puis vérifient qu'un appel sans transaction remet tous les soldes à zéro. + +### F5 — Meilleure période en un passage (Kadane) + +La somme de la meilleure période se terminant au jour courant est conservée. +Si cette somme est négative, le prochain jour démarre une nouvelle période ; +sinon, elle est prolongée. Le coût passe de `O(J³)` à **`O(J)`**, avec +**`O(1)`** de mémoire auxiliaire, et la complexité cyclomatique de **5 à 4**. + +La somme initiale est celle du premier jour : une série entièrement négative +renvoie bien un intervalle non vide. On redémarre uniquement pour une somme +strictement négative et on remplace le meilleur résultat uniquement pour +une somme strictement supérieure. Une somme nulle conserve ainsi le début +le plus ancien ; à égalité, le premier début puis la première fin sont +conservés comme dans les boucles initiales. Les **97 655 séries** de longueur +1 à 7 à valeurs dans `[-2, 2]` sont comparées à la version cubique, sur la +somme et sur les deux bornes : elles couvrent notamment les zéros, les +égalités et les séries entièrement négatives. diff --git a/banque.c b/banque.c index 3722e6d..f2a50f9 100644 --- a/banque.c +++ b/banque.c @@ -146,21 +146,25 @@ void total_par_jour(const Transaction *t, int n, long *totaux) } /* F5 : période de jours consécutifs dont la somme des soldes est maximale */ +/* Précondition : nb_jours > 0. En cas d'égalité, garder le premier intervalle. */ long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin) { long meilleur = totaux[0]; + long somme = totaux[0]; + int debut_courant = 0; *debut = 0; *fin = 0; - for (int i = 0; i < nb_jours; i++) { - for (int j = i; j < nb_jours; j++) { - long somme = 0; - for (int k = i; k <= j; k++) - somme += totaux[k]; - if (somme > meilleur) { - meilleur = somme; - *debut = i; - *fin = j; - } + for (int j = 1; j < nb_jours; j++) { + if (somme < 0) { + somme = totaux[j]; + debut_courant = j; + } else { + somme += totaux[j]; + } + if (somme > meilleur) { + meilleur = somme; + *debut = debut_courant; + *fin = j; } } return meilleur; diff --git a/tests/test_banque.c b/tests/test_banque.c index 4320a73..967a048 100644 --- a/tests/test_banque.c +++ b/tests/test_banque.c @@ -113,12 +113,54 @@ static void tester_totaux_jours(void) assert(totaux[j] == 0); } +static long periode_reference(const long *t, int n, int *debut, int *fin) +{ + long meilleur = t[0]; + *debut = 0; + *fin = 0; + for (int i = 0; i < n; i++) { + for (int j = i; j < n; j++) { + long somme = 0; + for (int k = i; k <= j; k++) + somme += t[k]; + if (somme > meilleur) { + meilleur = somme; + *debut = i; + *fin = j; + } + } + } + return meilleur; +} + +static void tester_periodes(void) +{ + long t[7]; + int nb_cas = 1; + for (int n = 1; n <= 7; n++) { + nb_cas *= 5; + for (int cas = 0; cas < nb_cas; cas++) { + int valeurs = cas; + for (int i = 0; i < n; i++) { + t[i] = valeurs % 5 - 2; + valeurs /= 5; + } + int debut, fin, debut_attendu, fin_attendue; + long attendu = periode_reference(t, n, &debut_attendu, &fin_attendue); + assert(meilleure_periode(t, n, &debut, &fin) == attendu); + assert(debut == debut_attendu); + assert(fin == fin_attendue); + } + } +} + int main(void) { tester_tri(); tester_clients_distincts(); tester_totaux_clients(); tester_totaux_jours(); + tester_periodes(); puts("Tests banque : OK"); return 0; }