Optimiser F5 avec Kadane en conservant les égalités

This commit is contained in:
rabot
2026-10-21 11:13:19 +02:00
parent b59e9700c7
commit 285afd80a7
3 changed files with 73 additions and 10 deletions
+17
View File
@@ -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.
+14 -10
View File
@@ -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;
+42
View File
@@ -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;
}