From 96abb3e2d0fb2b1f7419b93d1908208a3db91f3b Mon Sep 17 00:00:00 2001 From: Karl_FRAM Date: Wed, 21 Oct 2026 11:30:16 +0200 Subject: [PATCH 1/3] EXO 4 - optimisation F3 --- banque.c | 664 +++++++++++++++++++++++++++---------------------------- 1 file changed, 332 insertions(+), 332 deletions(-) diff --git a/banque.c b/banque.c index e4783a6..6126447 100644 --- a/banque.c +++ b/banque.c @@ -1,332 +1,332 @@ -/* - * R5.A.04 - Qualité Algorithmique - * TD Complexité algorithmique : analyse des transactions d'une banque - * - * Le programme génère des transactions pseudo-aléatoires (toujours les - * mêmes, grâce à une graine fixe), puis calcule plusieurs indicateurs - * et produit un rapport dans rapport.txt. - * - * L'empreinte affichée à la fin doit rester IDENTIQUE après vos - * optimisations : elle prouve que le résultat n'a pas changé. - * - * Interdit : modifier les constantes, la génération des données, - * le format du rapport, ou écrire les résultats « en dur ». - * - * Compilation : gcc -O2 banque.c -o banque - * Profiling : gcc -O0 -g -pg banque.c -o banque && ./banque && gprof ./banque gmon.out - */ - -#include -#include - -#define NB_TRANSACTIONS 30000 -#define NB_CLIENTS 2000 -#define NB_JOURS 1000 -#define NB_REQUETES 30000 -#define MONTANT_MONNAIE 400 -#define GRAINE 20261020UL - -typedef struct { - int id; - int client; - int jour; - long montant; /* en centimes, négatif pour un débit */ -} Transaction; - -/* ------------------------------------------------------------------ */ -/* Données (ne pas modifier) */ -/* ------------------------------------------------------------------ */ - -static unsigned long etat_alea = GRAINE; - -unsigned long alea(void) -{ - etat_alea = etat_alea * 6364136223846793005UL + 1442695040888963407UL; - return etat_alea >> 33; -} - -Transaction *generer_transactions(int n) -{ - Transaction *t = malloc(n * sizeof(Transaction)); - for (int i = 0; i < n; i++) { - t[i].id = i; - t[i].client = alea() % NB_CLIENTS; - t[i].jour = alea() % NB_JOURS; - if (i > 0 && alea() % 20 == 0) - t[i].montant = -t[alea() % i].montant; /* opération inverse */ - else - t[i].montant = (long)(alea() % 100001) - 50000; - } - for (int i = n - 1; i > 0; i--) { /* mélange des id */ - int j = alea() % (i + 1); - int tmp = t[i].id; - t[i].id = t[j].id; - t[j].id = tmp; - } - return t; -} - -/* ------------------------------------------------------------------ */ -/* Fonctions à analyser et à optimiser */ -/* ------------------------------------------------------------------ */ - -/* F1 : trie les transactions par montant croissant, puis par id */ -void trier_par_montant(Transaction *t, int n) -{ - for (int i = 1; i < n; i++) { - Transaction cle = t[i]; - int j = i - 1; - while (j >= 0 && (t[j].montant > cle.montant || - (t[j].montant == cle.montant && t[j].id > cle.id))) { - t[j + 1] = t[j]; - j--; - } - t[j + 1] = cle; - } -} - -/* F2 : nombre de clients ayant au moins une transaction */ -int nb_clients_distincts(const Transaction *t, int n) -{ - int nb = 0; - for (int i = 0; i < n; i++) { - int deja_vu = 0; - for (int j = 0; j < i; j++) { - if (t[j].client == t[i].client) { - deja_vu = 1; - break; - } - } - if (!deja_vu) - nb++; - } - return nb; -} - -/* F3 : solde total de chaque client */ -void total_par_client(const Transaction *t, int n, long *totaux) -{ - for (int c = 0; c < NB_CLIENTS; c++) { - totaux[c] = 0; - for (int i = 0; i < n; i++) - if (t[i].client == c) - totaux[c] += t[i].montant; - } -} - -/* F4 : solde total de chaque jour */ -void total_par_jour(const Transaction *t, int n, long *totaux) -{ - for (int j = 0; j < NB_JOURS; j++) { - totaux[j] = 0; - for (int i = 0; i < n; i++) - if (t[i].jour == j) - totaux[j] += t[i].montant; - } -} - -/* F5 : période de jours consécutifs dont la somme des soldes est maximale */ -long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin) -{ - long meilleur = totaux[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; - } - } - } - return meilleur; -} - -/* F6 : retrouve une transaction à partir de son id */ -const Transaction *rechercher_par_id(const Transaction *t, int n, int id) -{ - for (int i = 0; i < n; i++) - if (t[i].id == id) - return &t[i]; - return NULL; -} - -/* F7 : nombre de paires de transactions de montants opposés (a + b = 0) */ -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; -} - -/* F8 : nombre de façons de rendre une somme avec les pièces disponibles */ -static const int PIECES[] = {1, 2, 5, 10, 20, 50, 100, 200}; -#define NB_PIECES 8 - -long nb_facons_rendre(int somme, int nb_pieces) -{ - if (somme == 0) - return 1; - if (somme < 0 || nb_pieces == 0) - return 0; - return nb_facons_rendre(somme - PIECES[nb_pieces - 1], nb_pieces) + - nb_facons_rendre(somme, nb_pieces - 1); -} - -/* F9 : catégorie d'une transaction (pour les statistiques) */ -int categorie(const Transaction *t) -{ - if (t->montant < 0) { - if (t->montant < -20000) { - if (t->jour % 7 == 5 || t->jour % 7 == 6) - return 1; - else - return 2; - } else if (t->montant < -5000) { - return 3; - } else { - if (t->client % 10 == 0) - return 4; - return 5; - } - } else if (t->montant == 0) { - return 0; - } else { - if (t->montant > 30000) { - if (t->client % 10 == 0 && t->jour % 7 < 5) - return 6; - return 7; - } else if (t->montant > 10000) { - return 8; - } else if (t->montant > 1000) { - if (t->jour % 30 == 0) - return 9; - return 10; - } - return 11; - } -} - -/* F10 : ajoute une ligne à la fin du rapport */ -int longueur(const char *s) -{ - int n = 0; - while (s[n] != '\0') - n++; - return n; -} - -void ajouter_ligne(char *rapport, const char *ligne) -{ - int fin = longueur(rapport); - int i = 0; - while (ligne[i] != '\0') { - rapport[fin + i] = ligne[i]; - i++; - } - rapport[fin + i] = '\0'; -} - -/* ------------------------------------------------------------------ */ -/* Programme principal (à adapter si vous changez les signatures) */ -/* ------------------------------------------------------------------ */ - -unsigned long empreinte(const char *s) -{ - unsigned long h = 1469598103934665603UL; - for (int i = 0; s[i] != '\0'; i++) { - h ^= (unsigned char)s[i]; - h *= 1099511628211UL; - } - return h; -} - -int main(void) -{ - Transaction *t = generer_transactions(NB_TRANSACTIONS); - char *rapport = malloc(1 << 20); - char ligne[128]; - rapport[0] = '\0'; - - /* recherches par id, dans l'ordre d'origine */ - long somme_requetes = 0; - unsigned long etat = 12345; - for (int q = 0; q < NB_REQUETES; q++) { - etat = etat * 1103515245UL + 12345UL; - const Transaction *r = rechercher_par_id(t, NB_TRANSACTIONS, (int)((etat >> 8) % NB_TRANSACTIONS)); - if (r != NULL) - somme_requetes += r->montant; - } - - int nb_clients = nb_clients_distincts(t, NB_TRANSACTIONS); - - static long totaux_clients[NB_CLIENTS]; - total_par_client(t, NB_TRANSACTIONS, totaux_clients); - - static long totaux_jours[NB_JOURS]; - total_par_jour(t, NB_TRANSACTIONS, totaux_jours); - 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_facons = nb_facons_rendre(MONTANT_MONNAIE, NB_PIECES); - - /* rapport */ - snprintf(ligne, sizeof(ligne), "clients distincts;%d\n", nb_clients); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "somme des requetes;%ld\n", somme_requetes); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "meilleure periode;%d;%d;%ld\n", debut, fin, meilleure); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "paires opposees;%ld\n", nb_paires); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "facons de rendre %d;%ld\n", MONTANT_MONNAIE, nb_facons); - ajouter_ligne(rapport, ligne); - for (int c = 0; c < 12; c++) { - snprintf(ligne, sizeof(ligne), "categorie;%d;%d\n", c, categories[c]); - ajouter_ligne(rapport, ligne); - } - for (int c = 0; c < NB_CLIENTS; c++) { - snprintf(ligne, sizeof(ligne), "client;%d;%ld\n", c, totaux_clients[c]); - ajouter_ligne(rapport, ligne); - } - for (int j = 0; j < NB_JOURS; j++) { - snprintf(ligne, sizeof(ligne), "jour;%d;%ld\n", j, totaux_jours[j]); - ajouter_ligne(rapport, ligne); - } - for (int i = 0; i < NB_TRANSACTIONS; i += 10) { - snprintf(ligne, sizeof(ligne), "rang;%d;%d;%ld\n", i, t[i].id, t[i].montant); - ajouter_ligne(rapport, ligne); - } - - FILE *f = fopen("rapport.txt", "w"); - if (f != NULL) { - fputs(rapport, f); - fclose(f); - } - - printf("Clients distincts : %d\n", nb_clients); - printf("Somme des requêtes : %ld\n", somme_requetes); - printf("Meilleure période : jours %d à %d (%ld)\n", debut, fin, meilleure); - printf("Paires opposées : %ld\n", nb_paires); - printf("Façons de rendre %d : %ld\n", MONTANT_MONNAIE, nb_facons); - printf("Empreinte : %016lx\n", empreinte(rapport)); - - free(rapport); - free(t); - return 0; -} +/* + * R5.A.04 - Qualité Algorithmique + * TD Complexité algorithmique : analyse des transactions d'une banque + * + * Le programme génère des transactions pseudo-aléatoires (toujours les + * mêmes, grâce à une graine fixe), puis calcule plusieurs indicateurs + * et produit un rapport dans rapport.txt. + * + * L'empreinte affichée à la fin doit rester IDENTIQUE après vos + * optimisations : elle prouve que le résultat n'a pas changé. + * + * Interdit : modifier les constantes, la génération des données, + * le format du rapport, ou écrire les résultats « en dur ». + * + * Compilation : gcc -O2 banque.c -o banque + * Profiling : gcc -O0 -g -pg banque.c -o banque && ./banque && gprof ./banque gmon.out + */ + +#include +#include + +#define NB_TRANSACTIONS 30000 +#define NB_CLIENTS 2000 +#define NB_JOURS 1000 +#define NB_REQUETES 30000 +#define MONTANT_MONNAIE 400 +#define GRAINE 20261020UL + +typedef struct { + int id; + int client; + int jour; + long montant; /* en centimes, négatif pour un débit */ +} Transaction; + +/* ------------------------------------------------------------------ */ +/* Données (ne pas modifier) */ +/* ------------------------------------------------------------------ */ + +static unsigned long etat_alea = GRAINE; + +unsigned long alea(void) +{ + etat_alea = etat_alea * 6364136223846793005UL + 1442695040888963407UL; + return etat_alea >> 33; +} + +Transaction *generer_transactions(int n) +{ + Transaction *t = malloc(n * sizeof(Transaction)); + for (int i = 0; i < n; i++) { + t[i].id = i; + t[i].client = alea() % NB_CLIENTS; + t[i].jour = alea() % NB_JOURS; + if (i > 0 && alea() % 20 == 0) + t[i].montant = -t[alea() % i].montant; /* opération inverse */ + else + t[i].montant = (long)(alea() % 100001) - 50000; + } + for (int i = n - 1; i > 0; i--) { /* mélange des id */ + int j = alea() % (i + 1); + int tmp = t[i].id; + t[i].id = t[j].id; + t[j].id = tmp; + } + return t; +} + +/* ------------------------------------------------------------------ */ +/* Fonctions à analyser et à optimiser */ +/* ------------------------------------------------------------------ */ + +/* F1 : trie les transactions par montant croissant, puis par id */ +void trier_par_montant(Transaction *t, int n) +{ + for (int i = 1; i < n; i++) { + Transaction cle = t[i]; + int j = i - 1; + while (j >= 0 && (t[j].montant > cle.montant || + (t[j].montant == cle.montant && t[j].id > cle.id))) { + t[j + 1] = t[j]; + j--; + } + t[j + 1] = cle; + } +} + +/* F2 : nombre de clients ayant au moins une transaction */ +int nb_clients_distincts(const Transaction *t, int n) +{ + int nb = 0; + for (int i = 0; i < n; i++) { + int deja_vu = 0; + for (int j = 0; j < i; j++) { + if (t[j].client == t[i].client) { + deja_vu = 1; + break; + } + } + if (!deja_vu) + nb++; + } + return nb; +} + +/* F3 : solde total de chaque client en O(n + c) */ +void total_par_client(const Transaction *t, int n, long *totaux) +{ + for (int c = 0; c < NB_CLIENTS; c++) { + totaux[c] = 0; + } + for (int i = 0; i < n; i++) { + totaux[t[i].client] += t[i].montant; + } +} + +/* F4 : solde total de chaque jour */ +void total_par_jour(const Transaction *t, int n, long *totaux) +{ + for (int j = 0; j < NB_JOURS; j++) { + totaux[j] = 0; + for (int i = 0; i < n; i++) + if (t[i].jour == j) + totaux[j] += t[i].montant; + } +} + +/* F5 : période de jours consécutifs dont la somme des soldes est maximale */ +long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin) +{ + long meilleur = totaux[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; + } + } + } + return meilleur; +} + +/* F6 : retrouve une transaction à partir de son id */ +const Transaction *rechercher_par_id(const Transaction *t, int n, int id) +{ + for (int i = 0; i < n; i++) + if (t[i].id == id) + return &t[i]; + return NULL; +} + +/* F7 : nombre de paires de transactions de montants opposés (a + b = 0) */ +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; +} + +/* F8 : nombre de façons de rendre une somme avec les pièces disponibles */ +static const int PIECES[] = {1, 2, 5, 10, 20, 50, 100, 200}; +#define NB_PIECES 8 + +long nb_facons_rendre(int somme, int nb_pieces) +{ + if (somme == 0) + return 1; + if (somme < 0 || nb_pieces == 0) + return 0; + return nb_facons_rendre(somme - PIECES[nb_pieces - 1], nb_pieces) + + nb_facons_rendre(somme, nb_pieces - 1); +} + +/* F9 : catégorie d'une transaction (pour les statistiques) */ +int categorie(const Transaction *t) +{ + if (t->montant < 0) { + if (t->montant < -20000) { + if (t->jour % 7 == 5 || t->jour % 7 == 6) + return 1; + else + return 2; + } else if (t->montant < -5000) { + return 3; + } else { + if (t->client % 10 == 0) + return 4; + return 5; + } + } else if (t->montant == 0) { + return 0; + } else { + if (t->montant > 30000) { + if (t->client % 10 == 0 && t->jour % 7 < 5) + return 6; + return 7; + } else if (t->montant > 10000) { + return 8; + } else if (t->montant > 1000) { + if (t->jour % 30 == 0) + return 9; + return 10; + } + return 11; + } +} + +/* F10 : ajoute une ligne à la fin du rapport */ +int longueur(const char *s) +{ + int n = 0; + while (s[n] != '\0') + n++; + return n; +} + +void ajouter_ligne(char *rapport, const char *ligne) +{ + int fin = longueur(rapport); + int i = 0; + while (ligne[i] != '\0') { + rapport[fin + i] = ligne[i]; + i++; + } + rapport[fin + i] = '\0'; +} + +/* ------------------------------------------------------------------ */ +/* Programme principal (à adapter si vous changez les signatures) */ +/* ------------------------------------------------------------------ */ + +unsigned long empreinte(const char *s) +{ + unsigned long h = 1469598103934665603UL; + for (int i = 0; s[i] != '\0'; i++) { + h ^= (unsigned char)s[i]; + h *= 1099511628211UL; + } + return h; +} + +int main(void) +{ + Transaction *t = generer_transactions(NB_TRANSACTIONS); + char *rapport = malloc(1 << 20); + char ligne[128]; + rapport[0] = '\0'; + + /* recherches par id, dans l'ordre d'origine */ + long somme_requetes = 0; + unsigned long etat = 12345; + for (int q = 0; q < NB_REQUETES; q++) { + etat = etat * 1103515245UL + 12345UL; + const Transaction *r = rechercher_par_id(t, NB_TRANSACTIONS, (int)((etat >> 8) % NB_TRANSACTIONS)); + if (r != NULL) + somme_requetes += r->montant; + } + + int nb_clients = nb_clients_distincts(t, NB_TRANSACTIONS); + + static long totaux_clients[NB_CLIENTS]; + total_par_client(t, NB_TRANSACTIONS, totaux_clients); + + static long totaux_jours[NB_JOURS]; + total_par_jour(t, NB_TRANSACTIONS, totaux_jours); + 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_facons = nb_facons_rendre(MONTANT_MONNAIE, NB_PIECES); + + /* rapport */ + snprintf(ligne, sizeof(ligne), "clients distincts;%d\n", nb_clients); + ajouter_ligne(rapport, ligne); + snprintf(ligne, sizeof(ligne), "somme des requetes;%ld\n", somme_requetes); + ajouter_ligne(rapport, ligne); + snprintf(ligne, sizeof(ligne), "meilleure periode;%d;%d;%ld\n", debut, fin, meilleure); + ajouter_ligne(rapport, ligne); + snprintf(ligne, sizeof(ligne), "paires opposees;%ld\n", nb_paires); + ajouter_ligne(rapport, ligne); + snprintf(ligne, sizeof(ligne), "facons de rendre %d;%ld\n", MONTANT_MONNAIE, nb_facons); + ajouter_ligne(rapport, ligne); + for (int c = 0; c < 12; c++) { + snprintf(ligne, sizeof(ligne), "categorie;%d;%d\n", c, categories[c]); + ajouter_ligne(rapport, ligne); + } + for (int c = 0; c < NB_CLIENTS; c++) { + snprintf(ligne, sizeof(ligne), "client;%d;%ld\n", c, totaux_clients[c]); + ajouter_ligne(rapport, ligne); + } + for (int j = 0; j < NB_JOURS; j++) { + snprintf(ligne, sizeof(ligne), "jour;%d;%ld\n", j, totaux_jours[j]); + ajouter_ligne(rapport, ligne); + } + for (int i = 0; i < NB_TRANSACTIONS; i += 10) { + snprintf(ligne, sizeof(ligne), "rang;%d;%d;%ld\n", i, t[i].id, t[i].montant); + ajouter_ligne(rapport, ligne); + } + + FILE *f = fopen("rapport.txt", "w"); + if (f != NULL) { + fputs(rapport, f); + fclose(f); + } + + printf("Clients distincts : %d\n", nb_clients); + printf("Somme des requêtes : %ld\n", somme_requetes); + printf("Meilleure période : jours %d à %d (%ld)\n", debut, fin, meilleure); + printf("Paires opposées : %ld\n", nb_paires); + printf("Façons de rendre %d : %ld\n", MONTANT_MONNAIE, nb_facons); + printf("Empreinte : %016lx\n", empreinte(rapport)); + + free(rapport); + free(t); + return 0; +} -- 2.54.0 From bf16afd7279c2d8e5516fe4eb4efd6e8c675c4ae Mon Sep 17 00:00:00 2001 From: Karl_FRAM Date: Wed, 21 Oct 2026 11:30:59 +0200 Subject: [PATCH 2/3] EXO 4 - optimisation F3 --- banque | Bin 21160 -> 21160 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/banque b/banque index 0ae2b468574f5d6d707dd61f119e9b6a5fcfc01f..c38444be23ae4dfa5dfba4c270ce8692673394c3 100755 GIT binary patch literal 21160 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 Date: Wed, 21 Oct 2026 11:58:37 +0200 Subject: [PATCH 3/3] EXO 4 - optimisation F5 --- banque | Bin 21160 -> 21576 bytes banque.c | 392 +++++-------------------------------------------------- 2 files changed, 32 insertions(+), 360 deletions(-) diff --git a/banque b/banque index c38444be23ae4dfa5dfba4c270ce8692673394c3..b24d472e3f626018fdf3457b3ef4d731260e6d89 100755 GIT binary patch delta 8344 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 K#W>l^TMhu_SbUWL delta 7517 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 p^q= -#include - -#define NB_TRANSACTIONS 30000 -#define NB_CLIENTS 2000 -#define NB_JOURS 1000 -#define NB_REQUETES 30000 -#define MONTANT_MONNAIE 400 -#define GRAINE 20261020UL - -typedef struct { - int id; - int client; - int jour; - long montant; /* en centimes, négatif pour un débit */ -} Transaction; - -/* ------------------------------------------------------------------ */ -/* Données (ne pas modifier) */ -/* ------------------------------------------------------------------ */ - -static unsigned long etat_alea = GRAINE; - -unsigned long alea(void) -{ - etat_alea = etat_alea * 6364136223846793005UL + 1442695040888963407UL; - return etat_alea >> 33; -} - -Transaction *generer_transactions(int n) -{ - Transaction *t = malloc(n * sizeof(Transaction)); - for (int i = 0; i < n; i++) { - t[i].id = i; - t[i].client = alea() % NB_CLIENTS; - t[i].jour = alea() % NB_JOURS; - if (i > 0 && alea() % 20 == 0) - t[i].montant = -t[alea() % i].montant; /* opération inverse */ - else - t[i].montant = (long)(alea() % 100001) - 50000; - } - for (int i = n - 1; i > 0; i--) { /* mélange des id */ - int j = alea() % (i + 1); - int tmp = t[i].id; - t[i].id = t[j].id; - t[j].id = tmp; - } - return t; -} - -/* ------------------------------------------------------------------ */ -/* Fonctions à analyser et à optimiser */ -/* ------------------------------------------------------------------ */ - -/* F1 : trie les transactions par montant croissant, puis par id */ -void trier_par_montant(Transaction *t, int n) -{ - for (int i = 1; i < n; i++) { - Transaction cle = t[i]; - int j = i - 1; - while (j >= 0 && (t[j].montant > cle.montant || - (t[j].montant == cle.montant && t[j].id > cle.id))) { - t[j + 1] = t[j]; - j--; - } - t[j + 1] = cle; - } -} - -/* F2 : nombre de clients ayant au moins une transaction */ -int nb_clients_distincts(const Transaction *t, int n) -{ - int nb = 0; - for (int i = 0; i < n; i++) { - int deja_vu = 0; - for (int j = 0; j < i; j++) { - if (t[j].client == t[i].client) { - deja_vu = 1; - break; - } - } - if (!deja_vu) - nb++; - } - return nb; -} - -/* F3 : solde total de chaque client en O(n + c) */ -void total_par_client(const Transaction *t, int n, long *totaux) -{ - for (int c = 0; c < NB_CLIENTS; c++) { - totaux[c] = 0; - } - for (int i = 0; i < n; i++) { - totaux[t[i].client] += t[i].montant; - } -} - -/* F4 : solde total de chaque jour */ -void total_par_jour(const Transaction *t, int n, long *totaux) -{ - for (int j = 0; j < NB_JOURS; j++) { - totaux[j] = 0; - for (int i = 0; i < n; i++) - if (t[i].jour == j) - totaux[j] += t[i].montant; - } -} - -/* F5 : période de jours consécutifs dont la somme des soldes est maximale */ -long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin) -{ - long meilleur = totaux[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; - } - } - } - return meilleur; -} - -/* F6 : retrouve une transaction à partir de son id */ -const Transaction *rechercher_par_id(const Transaction *t, int n, int id) -{ - for (int i = 0; i < n; i++) - if (t[i].id == id) - return &t[i]; - return NULL; -} - -/* F7 : nombre de paires de transactions de montants opposés (a + b = 0) */ -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; -} - -/* F8 : nombre de façons de rendre une somme avec les pièces disponibles */ -static const int PIECES[] = {1, 2, 5, 10, 20, 50, 100, 200}; -#define NB_PIECES 8 - -long nb_facons_rendre(int somme, int nb_pieces) -{ - if (somme == 0) - return 1; - if (somme < 0 || nb_pieces == 0) - return 0; - return nb_facons_rendre(somme - PIECES[nb_pieces - 1], nb_pieces) + - nb_facons_rendre(somme, nb_pieces - 1); -} - -/* F9 : catégorie d'une transaction (pour les statistiques) */ -int categorie(const Transaction *t) -{ - if (t->montant < 0) { - if (t->montant < -20000) { - if (t->jour % 7 == 5 || t->jour % 7 == 6) - return 1; - else - return 2; - } else if (t->montant < -5000) { - return 3; - } else { - if (t->client % 10 == 0) - return 4; - return 5; - } - } else if (t->montant == 0) { - return 0; - } else { - if (t->montant > 30000) { - if (t->client % 10 == 0 && t->jour % 7 < 5) - return 6; - return 7; - } else if (t->montant > 10000) { - return 8; - } else if (t->montant > 1000) { - if (t->jour % 30 == 0) - return 9; - return 10; - } - return 11; - } -} - -/* F10 : ajoute une ligne à la fin du rapport */ -int longueur(const char *s) -{ - int n = 0; - while (s[n] != '\0') - n++; - return n; -} - -void ajouter_ligne(char *rapport, const char *ligne) -{ - int fin = longueur(rapport); - int i = 0; - while (ligne[i] != '\0') { - rapport[fin + i] = ligne[i]; - i++; - } - rapport[fin + i] = '\0'; -} - -/* ------------------------------------------------------------------ */ -/* Programme principal (à adapter si vous changez les signatures) */ -/* ------------------------------------------------------------------ */ - -unsigned long empreinte(const char *s) -{ - unsigned long h = 1469598103934665603UL; - for (int i = 0; s[i] != '\0'; i++) { - h ^= (unsigned char)s[i]; - h *= 1099511628211UL; - } - return h; -} - -int main(void) -{ - Transaction *t = generer_transactions(NB_TRANSACTIONS); - char *rapport = malloc(1 << 20); - char ligne[128]; - rapport[0] = '\0'; - - /* recherches par id, dans l'ordre d'origine */ - long somme_requetes = 0; - unsigned long etat = 12345; - for (int q = 0; q < NB_REQUETES; q++) { - etat = etat * 1103515245UL + 12345UL; - const Transaction *r = rechercher_par_id(t, NB_TRANSACTIONS, (int)((etat >> 8) % NB_TRANSACTIONS)); - if (r != NULL) - somme_requetes += r->montant; - } - - int nb_clients = nb_clients_distincts(t, NB_TRANSACTIONS); - - static long totaux_clients[NB_CLIENTS]; - total_par_client(t, NB_TRANSACTIONS, totaux_clients); - - static long totaux_jours[NB_JOURS]; - total_par_jour(t, NB_TRANSACTIONS, totaux_jours); - 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_facons = nb_facons_rendre(MONTANT_MONNAIE, NB_PIECES); - - /* rapport */ - snprintf(ligne, sizeof(ligne), "clients distincts;%d\n", nb_clients); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "somme des requetes;%ld\n", somme_requetes); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "meilleure periode;%d;%d;%ld\n", debut, fin, meilleure); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "paires opposees;%ld\n", nb_paires); - ajouter_ligne(rapport, ligne); - snprintf(ligne, sizeof(ligne), "facons de rendre %d;%ld\n", MONTANT_MONNAIE, nb_facons); - ajouter_ligne(rapport, ligne); - for (int c = 0; c < 12; c++) { - snprintf(ligne, sizeof(ligne), "categorie;%d;%d\n", c, categories[c]); - ajouter_ligne(rapport, ligne); - } - for (int c = 0; c < NB_CLIENTS; c++) { - snprintf(ligne, sizeof(ligne), "client;%d;%ld\n", c, totaux_clients[c]); - ajouter_ligne(rapport, ligne); - } - for (int j = 0; j < NB_JOURS; j++) { - snprintf(ligne, sizeof(ligne), "jour;%d;%ld\n", j, totaux_jours[j]); - ajouter_ligne(rapport, ligne); - } - for (int i = 0; i < NB_TRANSACTIONS; i += 10) { - snprintf(ligne, sizeof(ligne), "rang;%d;%d;%ld\n", i, t[i].id, t[i].montant); - ajouter_ligne(rapport, ligne); - } - - FILE *f = fopen("rapport.txt", "w"); - if (f != NULL) { - fputs(rapport, f); - fclose(f); - } - - printf("Clients distincts : %d\n", nb_clients); - printf("Somme des requêtes : %ld\n", somme_requetes); - printf("Meilleure période : jours %d à %d (%ld)\n", debut, fin, meilleure); - printf("Paires opposées : %ld\n", nb_paires); - printf("Façons de rendre %d : %ld\n", MONTANT_MONNAIE, nb_facons); - printf("Empreinte : %016lx\n", empreinte(rapport)); - - free(rapport); - free(t); - return 0; -} -======= /* * R5.A.04 - Qualité Algorithmique * TD Complexité algorithmique : analyse des transactions d'une banque @@ -422,28 +88,29 @@ void trier_par_montant(Transaction *t, int n) /* F2 : nombre de clients ayant au moins une transaction */ int nb_clients_distincts(const Transaction *t, int n) { - int clients_vus[NB_CLIENTS] = {0}; int nb = 0; - for (int i = 0; i < n; i++) { - int client = t[i].client; - if (!clients_vus[client]) { - clients_vus[client] = 1; - nb++; + int deja_vu = 0; + for (int j = 0; j < i; j++) { + if (t[j].client == t[i].client) { + deja_vu = 1; + break; + } } + if (!deja_vu) + nb++; } - return nb; } -/* F3 : solde total de chaque client */ +/* F3 : solde total de chaque client en O(n + c) */ void total_par_client(const Transaction *t, int n, long *totaux) { for (int c = 0; c < NB_CLIENTS; c++) { totaux[c] = 0; - for (int i = 0; i < n; i++) - if (t[i].client == c) - totaux[c] += t[i].montant; + } + for (int i = 0; i < n; i++) { + totaux[t[i].client] += t[i].montant; } } @@ -452,30 +119,36 @@ void total_par_jour(const Transaction *t, int n, long *totaux) { for (int j = 0; j < NB_JOURS; j++) { totaux[j] = 0; + for (int i = 0; i < n; i++) + if (t[i].jour == j) + totaux[j] += t[i].montant; } - - for (int i = 0; i < n; i++) - totaux[t[i].jour] += t[i].montant; } -/* F5 : période de jours consécutifs dont la somme des soldes est maximale */ +/* F5 : période de jours consécutifs dont la somme des soldes est maximale en O(J) */ long meilleure_periode(const long *totaux, int nb_jours, int *debut, int *fin) { long meilleur = totaux[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; - } + + long somme_courante = totaux[0]; + int debut_courant = 0; + + for (int j = 1; j < nb_jours; j++) { + if (somme_courante < 0) { + somme_courante = totaux[j]; + debut_courant = j; + } else { + somme_courante += totaux[j]; + } + if (somme_courante > meilleur) { + meilleur = somme_courante; + *debut = debut_courant; + *fin = j; } } + return meilleur; } @@ -663,4 +336,3 @@ int main(void) free(t); return 0; } ->>>>>>> 97155f26889184ac9ab593d6aadb23cbdbce96c2 -- 2.54.0