Corrigé Mines-Ponts 2026 Informatique II MPI — Partie 2 (2.1 et 2.2) (Q6 à Q19) : Le monde en mémoire : listes chaînées et représentation CSR
Sujet officiel du concours Mines-Ponts, session 2026, épreuve Informatique II MPI. Corrigé rédigé par Ibrahim Alame.
Sujet officiel (PDF, site du concours)
Énoncé
Le monde est un graphe orienté pondéré : les salles sont les sommets, numérotés de à , les passages sont les arcs, de coûts strictement positifs. Les en-têtes standards (assert.h, stdbool.h, stdlib.h, …) sont supposés inclus.
2.1 Listes chaînées.
Chaque salle porte la liste chaînée de ses passages sortants (NULL si aucun) ; m->salles est un tableau de m->taille pointeurs, et m->salles[id] pointe vers la salle d'identifiant id.
struct _passage {
int cout;
int sortie;
struct _passage* suivant;
};
typedef struct _passage passage;
struct _salle {
int id;
passage* passages;
};
typedef struct _salle salle;
struct _monde {
salle** salles;
int taille;
};
typedef struct _monde monde;
Q6. Écrire monde* monde_init(int n), qui alloue un monde de n salles aux listes de passages vides.
Q7. Écrire int monde_degre(monde* m, int s) : degré sortant de la salle s.
Q8. À l'aide de monde_degre, écrire int monde_sommeDegres(monde* m) : nombre total de passages.
Q9. Écrire int monde_coutTotal(monde* m) : somme des coûts de tous les passages.
Q10. Entiers et pointeurs sur 32 bits : occupation mémoire en octets de cette représentation, pour salles et passages.
Q11. Avec 64 Ko et quatre passages sortants par salle en moyenne, ordre de grandeur du nombre maximal de salles, parmi , , …, .
2.2 Représentation CSR.
Trois tableaux : sorties (destinations de tous les passages, rangées salle par salle), couts (même taille, coût du passage correspondant) et indices, de taille : les passages sortants de la salle s occupent les cases , et la sentinelle indices[ns] vaut .
struct _mondeCSR {
int* sorties;
int* indices;
int* couts;
int nb_salles;
};
typedef struct _mondeCSR mondeCSR;
Q12. Dessiner le graphe de sorties = \{1,3,2,0,4,1,2\}, indices = \{0,2,3,5,6,7\}, couts = \{2,5,1,4,3,6,2\}.
Q13. Écrire mondeCSR* mondeCSR_init(int ns, int np) : allocation seule, sans initialiser le contenu.
Q14. Écrire int mondeCSR_degre(mondeCSR* mc, int s).
Q15. Écrire int mondeCSR_sommeDegres(mondeCSR* mc).
Q16. Écrire int mondeCSR_coutTotal(mondeCSR* mc).
Q17. Écrire mondeCSR* monde_vers_CSR(monde* m), qui construit la représentation CSR du même monde.
Q18. Occupation mémoire en octets de la représentation CSR (entiers sur 32 bits).
Q19. Comparer les occupations des questions 10 et 18 en fonction de et ; conclure.
Corrigé
Tous les programmes de cette partie ont été compilés (gcc -Wall -Wextra -std=c99, sans avertissement) et exécutés : on a construit en listes chaînées le monde de Q12, vérifié degrés, somme des degrés () et coût total () dans les deux représentations, et contrôlé que monde_vers_CSR redonne exactement les trois tableaux de l'énoncé ; cas limites : monde de salle, salles sans passage. L'outil leaks ne signale aucune fuite.
Q6. Trois niveaux d'allocation : la structure monde, le tableau de n pointeurs, puis chacune des n salles, dont on initialise les deux champs.
monde* monde_init(int n) {
assert(n >= 0);
monde* m = malloc(sizeof(monde));
assert(m != NULL);
m->taille = n;
m->salles = malloc(n * sizeof(salle*));
assert(n == 0 || m->salles != NULL);
for (int i = 0; i < n; i++) {
m->salles[i] = malloc(sizeof(salle));
assert(m->salles[i] != NULL);
m->salles[i]->id = i; /* id = indice dans le tableau */
m->salles[i]->passages = NULL; /* liste de passages vide */
}
return m;
}
Le tableau contient des salle*, d'où sizeof(salle*) ; chaque salle est une salle, d'où sizeof(salle). L'identifiant vaut l'indice, comme l'exige l'énoncé. (Le test n == 0 dans l'assertion tient compte de ce que malloc(0) peut renvoyer NULL.) Coût : allocations, .
Ce que le correcteur attend : l'allocation individuelle de chaque salle et la mise à NULL des listes ; le jury a relevé l'oubli de l'une ou l'autre, et la confusion entre la taille d'une structure et celle d'un pointeur.
Q7. Parcours de la liste en suivant le champ suivant :
int monde_degre(monde* m, int s) {
assert(m != NULL && 0 <= s && s < m->taille);
int d = 0;
for (passage* p = m->salles[s]->passages; p != NULL; p = p->suivant) {
d++;
}
return d;
}
Invariant : d est le nombre de maillons déjà dépassés, ceux qui précèdent p. La boucle s'arrête quand p vaut NULL, donc après le dernier maillon : d est la longueur de la liste. Elle termine car la liste, construite par des allocations successives, est finie et acyclique. Coût . La condition p->suivant != NULL oublierait le dernier maillon (et déréférencerait NULL sur une liste vide).
Q8. On réutilise monde_degre, comme demandé :
int monde_sommeDegres(monde* m) {
assert(m != NULL);
int total = 0;
for (int s = 0; s < m->taille; s++) {
total += monde_degre(m, s);
}
return total;
}
Chaque passage appartient à la liste de sa salle d'entrée et à elle seule : la somme des degrés sortants est le nombre de passages. Coût .
Q9. Double boucle : sur les salles, puis sur la liste de chacune.
int monde_coutTotal(monde* m) {
assert(m != NULL);
int total = 0;
for (int s = 0; s < m->taille; s++) {
for (passage* p = m->salles[s]->passages; p != NULL; p = p->suivant) {
total += p->cout;
}
}
return total;
}
Chaque passage est vu une fois exactement (même argument qu'en Q8) ; coût .
100 % gratuit
La suite du corrigé est sur Adloun
Le corrigé rédigé en entier, question par question, et le tuteur pour poser des questions sur ce sujet.
Voir le corrigé complet, gratuitementInscription gratuite en 30 secondes (e-mail, nom d'utilisateur, mot de passe, classe ou profil), sans carte bancaire : arrivée directe sur le corrigé.