From c84ff59ec38672088b76147aeb26f71cf03eafcd Mon Sep 17 00:00:00 2001 From: Ryad MEHIRI Date: Wed, 21 Oct 2026 10:55:16 +0200 Subject: [PATCH] =?UTF-8?q?F7=20:=20compter=20les=20paires=20oppos=C3=A9es?= =?UTF-8?q?=20par=20dichotomie=20(O(n=C2=B2)=20=E2=86=92=20O(n=20log=20n))?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La double boucle testait les n(n-1)/2 = 450 millions de paires. Sur le tableau trié par F1, deux recherches dichotomiques donnent en O(log n) le nombre de transactions de montant -v. On somme ces effectifs, on retire les montants nuls (comptés avec eux-mêmes) et on divise par 2 (chaque paire est vue deux fois). F7 est donc appelée après le tri dans main. Temps (-O2) : 0,92 s → 0,25 s. Empreinte inchangée (ff68d260a7a58441). Co-Authored-By: Claude Opus 5.5 --- banque.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/banque.c b/banque.c index ac3ae9a..8e4be4f 100644 --- a/banque.c +++ b/banque.c @@ -163,15 +163,37 @@ const Transaction *rechercher_par_id(const Transaction *t, const int *position, return &t[position[id]]; } -/* F7 : nombre de paires de transactions de montants opposés (a + b = 0) */ +/* Premier indice i tel que t[i].montant >= v, dans t trié par montant + * croissant (recherche dichotomique, O(log n)). */ +int premier_indice(const Transaction *t, int n, long v) +{ + int debut = 0, fin = n; + while (debut < fin) { + int milieu = (debut + fin) / 2; + if (t[milieu].montant < v) + debut = milieu + 1; + else + fin = milieu; + } + return debut; +} + +/* Nombre de transactions de montant v, dans t trié par montant croissant */ +int effectif(const Transaction *t, int n, long v) +{ + return premier_indice(t, n, v + 1) - premier_indice(t, n, v); +} + +/* F7 : nombre de paires de transactions de montants opposés (a + b = 0). + * t doit être trié par montant (F1). On compte, pour chaque transaction, les + * transactions de montant opposé : chaque paire est vue deux fois, et chaque + * montant nul se compte lui-même une fois en trop. */ long nb_paires_opposees(const Transaction *t, int n) { long nb = 0; for (int i = 0; i < n; i++) - for (int j = i + 1; j < n; j++) - if (t[i].montant + t[j].montant == 0) - nb++; - return nb; + nb += effectif(t, n, -t[i].montant); + return (nb - effectif(t, n, 0)) / 2; } /* F8 : nombre de façons de rendre une somme avec les pièces disponibles */ @@ -279,13 +301,12 @@ int main(void) int debut, fin; long meilleure = meilleure_periode(totaux_jours, NB_JOURS, &debut, &fin); - long nb_paires = nb_paires_opposees(t, NB_TRANSACTIONS); - int categories[12] = {0}; for (int i = 0; i < NB_TRANSACTIONS; i++) categories[categorie(&t[i])]++; trier_par_montant(t, NB_TRANSACTIONS); + long nb_paires = nb_paires_opposees(t, NB_TRANSACTIONS); /* a besoin du tri */ long nb_facons = nb_facons_rendre(MONTANT_MONNAIE, NB_PIECES);