A. Fonction ReLU
La fonction d'activation Rectified Linear Unit (ReLU) est une fonction mathématique simple et largement utilisée en apprentissage automatique. Elle est définie de manière segmentée :
- Si la valeur d'entrée \(x\) est inférieure ou égale à 0, la fonction retourne 0.
- Si la valeur d'entrée \(x\) est supérieure à 0, la fonction retourne \(x\) elle-même.
Cette logique peut être implémentée efficacement en C à l'aide d'une instruction conditionnelle if-else.
#include <stdio.h>
int main(void) {
int input_val; // Déclaration d'une variable pour la valeur d'entrée
scanf("%d", &input_val); // Lecture de l'entier fourni par l'utilisateur
if (input_val <= 0) { // Vérifie si la valeur est négative ou nulle
printf("0"); // Si oui, affiche 0
} else { // Sinon (la valeur est positive)
printf("%d", input_val); // Affiche la valeur elle-même
}
return 0; // Termine le programme avec succès
}
B. Somme d'une Séquence Spécifique
Ce problème consiste à calculer la somme des termes d'une séquence où chaque terme est formé en répétant un chiffre de base. Par exemple, pour un chiffre a et n termes, la séquence serait a, aa, aaa, .... La somme correspondante serait a + aa + aaa + ....
Étant donné que le nombre de termes n peut aller jusqu'à 16, la somme résultante peut devenir très grande, dépassant la capacité d'un type int standard. Il est crucial d'utiliser le type long long en C pour stocker la somme et les termes intermédiaires afin d'éviter les débordements (overflows).
Il est également important de noter que l'utilisation du type double n'est pas recommandée pour ce type de calcul. Le double est un format à virgule flottante qui offre une précision limitée (généralement environ 15-17 chiffres décimaux significatifs) et peut introduire des erreurs d'arrondi lors de la manipulation de grands nombres entiers, surtout si leur magnitude dépasse la précision de la mantisse (52 bits selon la norme IEEE 754).
#include <stdio.h>
int main(void) {
int chiffre_base; // Le chiffre 'a' qui compose chaque terme
int nombre_termes; // Le nombre 'n' de termes dans la séquence
long long somme_totale = 0; // Accumule la somme des termes (utilise long long pour éviter le débordement)
long long terme_courant = 0; // Le terme actuel de la séquence (a, aa, aaa, ...)
// Lecture du chiffre de base et du nombre de termes depuis l'entrée standard
scanf("%d %d", &chiffre_base, &nombre_termes);
// Boucle pour générer chaque terme et l'ajouter à la somme totale
for (int i = 0; i < nombre_termes; i++) {
// Construit le terme suivant : ex. si terme_courant est 'a', il devient 'aa'
terme_courant = terme_courant * 10 + chiffre_base;
somme_totale += terme_courant; // Ajoute le terme au total cumulé
}
// Affiche la somme calculée sur la sortie standard
printf("%lld", somme_totale);
return 0; // Indique que le programme s'est terminé avec succès
}
C. Détection de Cinq Matinées Consécutives
Le problème demande de déterminer si, dans une séquence d'entrées binaires (0 ou 1), il existe au moins cinq "1" consécutifs. Chaque "1" représente la présence d'un cours à 8h du matin, et "0" son absence.
La solution implique de maintenir un compteur qui s'incrémente chaque fois qu'un "1" est rencontré. Si un "0" est lu, le compteur est réinitialisé à zéro, car la séquence de "1" consécutifs est rompue. Dès que le compteur atteint ou dépasse la valeur de 5, nous savons que la condition est remplie et le programme peut s'arrêter en affichant "Oui". Si la fin de la séquence est atteinte sans que le compteur n'ait jamais atteint 5, le programme affiche "Non".
#include <stdio.h>
int main(void) {
int nombre_elements; // Le nombre total d'entrées (jours)
scanf("%d", &nombre_elements); // Lecture de la quantité d'entrées
int compteur_sequence = 0; // Compteur pour les '1' consécutifs
// Parcours de chaque élément de la séquence
for (int i = 0; i < nombre_elements; ++i) {
int valeur_actuelle; // La valeur actuelle (0 ou 1)
scanf("%d", &valeur_actuelle); // Lecture de la valeur pour l'élément courant
if (valeur_actuelle == 1) { // Si la valeur est '1'
compteur_sequence++; // Incrémente le compteur de séquence
} else { // Si la valeur est '0'
compteur_sequence = 0; // Réinitialise le compteur
}
// Vérifie si la séquence de 5 '1' consécutifs est atteinte
if (compteur_sequence == 5) {
printf("Oui"); // Si oui, affiche "Oui"
return 0; // Termine le programme immédiatement
}
}
// Si la boucle se termine sans trouver 5 '1' consécutifs
printf("Non"); // Affiche "Non"
return 0; // Termine le programme
}
D. Localisation d'une Coordonnée dans une Matrice
Ce problème demande de trouver la position (ligne et colonne) d'une valeur spécifique k au sein d'une matrice carrée de dimension N x N. Les coordonnées doivent être affichées en utilisant un indexation de base 1 (c'est-à-dire que la première ligne est 1, la première colonne est 1).
La méthode la plus directe est de parcourir la matrice élément par élément en utilisant des boucles for imbriquées. Dès que la valeur k est trouvée, ses coordonnées (ligne et colonne actuelles) sont affichées, et le programme peut se terminer immédiatement, car il n'est pas nécessaire de continuer la recherche.
#include <stdio.h>
int main(void) {
int dimension_matrice; // La dimension N de la matrice (N x N)
int valeur_recherchee; // La valeur K à localiser dans la matrice
scanf("%d %d", &dimension_matrice, &valeur_recherchee); // Lecture de N et K
// Parcours de la matrice ligne par ligne (l'indice commence à 1)
for (int ligne_idx = 1; ligne_idx <= dimension_matrice; ++ligne_idx) {
// Parcours de chaque colonne dans la ligne actuelle (l'indice commence à 1)
for (int col_idx = 1; col_idx <= dimension_matrice; ++col_idx) {
int element_actuel; // L'élément lu à la position (ligne_idx, col_idx)
scanf("%d", &element_actuel); // Lecture de l'élément de la matrice
// Vérifie si l'élément actuel correspond à la valeur recherchée
if (element_actuel == valeur_recherchee) {
// Si trouvé, affiche les coordonnées (ligne, colonne)
printf("%d %d", ligne_idx, col_idx);
return 0; // Termine le programme immédiatement
}
}
}
// Si la valeur n'est pas trouvée après avoir parcouru toute la matrice,
// le programme se termine ici (aucune sortie n'est requise dans ce cas selon l'énoncé implicite).
return 0;
}
E. Évaluation de Performance de Course
Ce problème consiste à évaluer des performances de course données en minutes et secondes. Chaque performance est convertie en un nombre total de secondes pour faciliter la comparaison. Ensuite, ces temps sont classifiés en catégories ("Excellent", "Bon", "Admis", "Échec") et le nombre total d'échecs est comptabilisé.
L'entrée des performances se fait de manière séquentielle, et la lecture se termine lorsqu'une valeur sentinelle de -1 est rencontrée pour les minutes. Un compteur est utilisé pour suivre le nombre d'échecs.
#include <stdio.h>
int main(void) {
int mins_entrees; // Variable pour stocker les minutes lues
int secs_entrees; // Variable pour stocker les secondes lues
int compte_echecs = 0; // Compteur pour le nombre de performances "Échec"
// Lecture initiale des minutes pour amorcer la boucle
scanf("%d", &mins_entrees);
// Boucle tant que la valeur des minutes n'est pas le signal de fin (-1)
while (mins_entrees != -1) {
scanf("%d", &secs_entrees); // Lecture des secondes correspondantes
// Conversion du temps total en secondes pour faciliter la comparaison
int temps_total_en_secondes = mins_entrees * 60 + secs_entrees;
// Évaluation et classification de la performance
if (temps_total_en_secondes <= 207) {
printf("Excellent\n");
} else if (temps_total_en_secondes <= 222) {
printf("Bon\n");
} else if (temps_total_en_secondes <= 272) {
printf("Admis\n");
} else {
printf("Échec\n");
compte_echecs++; // Incrémente le compteur d'échecs
}
// Lecture des minutes pour la prochaine itération de la boucle
scanf("%d", &mins_entrees);
}
// Affiche le nombre total de performances classées comme "Échec"
printf("%d", compte_echecs);
return 0; // Termine le programme
}
F. Simulation de Marche Bidimensionnelle
Ce problème consiste à simuler le mouvement d'un objet (un robot, une personne, etc.) sur un plan 2D. L'objet commence à la position (0,0) et effectue une série d'étapes. Chaque étape est définie par une direction (1: Est, 2: Ouest, 3: Sud, 4: Nord) et une longueur de pas. Le but est de calculer la position finale (coordonnées X et Y) de l'objet et la distance totale parcourue.
La solution implique de maintenir deux variables pour les coordonnées actuelles (coord_x et coord_y) et une variable pour la somme des longueurs de pas (distance_totale_parcourue). Pour chaque étape, les coordonnées sont mises à jour en fonction de la direction et de la longueur, et la longueur est ajoutée à la distance totale.
#include <stdio.h>
int main(void) {
int nombre_pas; // Nombre total de pas que l'objet effectuera
scanf("%d", &nombre_pas); // Lecture du nombre de pas
long long coord_x_actuelle = 0; // Coordonnée X de la position actuelle, initialisée à 0
long long coord_y_actuelle = 0; // Coordonnée Y de la position actuelle, initialisée à 0
long long distance_cumulee = 0; // Somme de toutes les longueurs de pas parcourues
// Boucle pour traiter chaque pas de mouvement
for (int i = 0; i < nombre_pas; ++i) {
int sens_mouvement; // La direction du pas (1=Est, 2=Ouest, 3=Sud, 4=Nord)
int longueur_mouvement; // La distance parcourue lors de ce pas
scanf("%d %d", &sens_mouvement, &longueur_mouvement); // Lecture de la direction et de la longueur
distance_cumulee += longueur_mouvement; // Ajoute la longueur du pas à la distance totale
// Mise à jour des coordonnées en fonction du sens de mouvement
switch (sens_mouvement) {
case 1: // Mouvement vers l'Est (X augmente)
coord_x_actuelle += longueur_mouvement;
break;
case 2: // Mouvement vers l'Ouest (X diminue)
coord_x_actuelle -= longueur_mouvement;
break;
case 3: // Mouvement vers le Sud (Y diminue)
coord_y_actuelle -= longueur_mouvement;
break;
case 4: // Mouvement vers le Nord (Y augmente)
coord_y_actuelle += longueur_mouvement;
break;
}
}
// Affiche les coordonnées finales de l'objet
printf("%lld %lld\n", coord_x_actuelle, coord_y_actuelle);
// Affiche la distance totale parcourue
printf("%lld\n", distance_cumulee);
return 0; // Termine le programme avec succès
}
G. Construction d'un Complément Numérique
Ce problème présente un grand nombre (dont la taille dépasse les types int ou long long) donné sous forme de ses chiffres individuels. L'objectif est de construire un nouveau nombre tel que, si on additionnait les deux nombres (le nombre donné et le nouveau nombre), le résultat serait un nombre composé uniquement de 9s, sauf pour le dernier chiffre qui serait 0 (ce qui implique une retenue de 1). Plus précisément, le problème demande de trouver un nombre X de N chiffres tel que si le nombre d'entrée Num a N chiffres, alors Num + X = 10^N (par exemple, si Num = 291 et N=3, X = 709 car 291 + 709 = 1000).
La soluiton consiste à traiter chaque chiffre individuellement, en partant du moins significatif au plus significatif. Pour le chiffre le plus à droite (moins significatif) du nombre d'entrée, le chiffre correspondant du nombre X est calculé comme 10 - (chiffre_d'entrée). Pour tous les autres chfifres (plus significatifs), le chiffre de X est 9 - (chiffre_d'entrée). Une attention particulière doit être portée à la suppression des zéros non significatifs lors de l'affichage du résultat, à moins que le résultat entier soit zéro (ce qui est peu probable avec cette logique).
#include <stdio.h>
int main(void) {
int nb_chiffres; // Nombre total de chiffres dans le nombre d'entrée
scanf("%d", &nb_chiffres); // Lecture de la quantité de chiffres (N)
// Tableau pour stocker les chiffres du nombre d'entrée,
// où chiffres_entree[0] est le chiffre le plus significatif
// et chiffres_entree[nb_chiffres-1] est le moins significatif.
int chiffres_entree[nb_chiffres];
for (int i = 0; i < nb_chiffres; ++i) {
scanf("%d", &chiffres_entree[i]); // Lecture de chaque chiffre
}
// Tableau pour stocker les chiffres du nombre résultant (X)
int chiffres_resultat[nb_chiffres];
// Calcul des chiffres du résultat en commençant par le chiffre le moins significatif
// (qui est à l'indice nb_chiffres-1 dans notre tableau)
for (int i = nb_chiffres - 1; i >= 0; --i) {
if (i == nb_chiffres - 1) { // Si c'est le chiffre le plus à droite (moins significatif)
chiffres_resultat[i] = 10 - chiffres_entree[i];
} else { // Pour tous les autres chiffres plus significatifs
chiffres_resultat[i] = 9 - chiffres_entree[i];
}
}
// Affichage des chiffres du résultat, en gérant les zéros non significatifs.
// Par exemple, si le résultat est 009, on doit afficher 9. Si c'est 0, on affiche 0.
int est_premier_chiffre_non_zero = 0; // Drapeau pour suivre si un chiffre non-zéro a été imprimé
for (int i = 0; i < nb_chiffres; ++i) {
// Affiche le chiffre si :
// 1. Il n'est pas zéro, OU
// 2. Un chiffre non-zéro a déjà été affiché (donc ce zéro est significatif), OU
// 3. C'est le tout dernier chiffre du nombre (même s'il est zéro et qu'il n'y a pas eu de chiffres non-zéro avant)
if (chiffres_resultat[i] != 0 || est_premier_chiffre_non_zero || (i == nb_chiffres - 1)) {
printf("%d", chiffres_resultat[i]);
est_premier_chiffre_non_zero = 1; // Marque qu'un chiffre a été affiché (potentiellement non-zéro)
}
}
return 0; // Termine le programme
}
H. Périmètre Minimal Englobant
Le problème demande de calculer le périmètre du plus petit rectangle capable d'englober un ensemble de N rectangles individuels. On suppose que tous les rectangles individuels sont positionnés de manière à ce que leur coin inférieur gauche se trouve à l'origine (0,0) d'un système de coordonnées.
Dans cette configuration, le rectangle englobant aura sa largeur maximale déterminée par la plus grande largeur de tous les rectangles individuels, et sa hauteur maximale par la plus grande hauteur de tous les rectangles individuels. Le périmètre de ce rectangle englobant est alors simplement 2 * (largeur_maximale + hauteur_maximale).
La solution consiste donc à parcourir tous les rectangles donnés, à trouver la largeur maximale et la hauteur maximale parmi eux, puis à calculer le périmètre à partir de ces deux valeurs.
#include <stdio.h>
int main(void) {
int nombre_formes; // Le nombre total de rectangles
scanf("%d", &nombre_formes); // Lecture du nombre de rectangles
int largeur_max_trouvee = 0; // Variable pour garder la plus grande largeur rencontrée
int hauteur_max_trouvee = 0; // Variable pour garder la plus grande hauteur rencontrée
// Parcours de chaque rectangle pour trouver les dimensions maximales
for (int i = 0; i < nombre_formes; ++i) {
int largeur_courante; // Largeur du rectangle actuel
int hauteur_courante; // Hauteur du rectangle actuel
scanf("%d %d", &largeur_courante, &hauteur_courante); // Lecture des dimensions
// Met à jour la largeur maximale si la largeur du rectangle courant est plus grande
if (largeur_courante > largeur_max_trouvee) {
largeur_max_trouvee = largeur_courante;
}
// Met à jour la hauteur maximale si la hauteur du rectangle courant est plus grande
if (hauteur_courante > hauteur_max_trouvee) {
hauteur_max_trouvee = hauteur_courante;
}
}
// Calcul et affichage du périmètre du rectangle englobant
printf("%d\n", (largeur_max_trouvee + hauteur_max_trouvee) * 2);
return 0; // Termine le programme
}