Adloun

Corrigé CCINP 2025 Informatique MP — Partie III (1) (Q10 à Q17) : Graphes pondérés en OCaml et composantes connexes

Sujet officiel du concours CCINP, session 2025, épreuve Informatique MP. Corrigé rédigé par Ibrahim Alame.

Sujet officiel (PDF, site du concours)

Énoncé

Le sujet rappelle Array.make, Array.length, a.(i), a.(i) <- e, List.iter, la boucle for (bornes incluses) et les fonctions max et min : 'a -> 'a -> 'a.

Q10. Écrire max_tab : int array -> int, qui renvoie le plus grand élément d'un tableau non vide, en temps linéaire justifié.

Un graphe pondéré de sommets () est représenté par listes d'adjacence pondérées : g.(i) contient les couples pour les voisins de , chaque arête figurant dans les listes de ses deux extrémités, avec le même poids.


type graphe = (int * float) list array

let nb_sommets g = Array.length g

Sur le graphe de la figure 2 ci-dessous, g.(0) vaut par exemple [(2, 24.0); (6, 21.0); (7, 18.0); (8, 6.0)].

Q11. Donner une valeur possible de g.(7).

Une arête est représentée une seule fois, par le triplet avec et . Les poids étant distincts, l'ordre < d'OCaml (lexicographique) compare deux arêtes selon leurs poids.

Q12. Écrire ajoute_arete : graphe -> (float * int * int) -> unit (arête absente au départ), en temps constant.
Q13. Écrire toutes_les_aretes : graphe -> (float * int * int) list, en justifié.
Q14. Écrire récursivement min_arete : (float * int * int) list -> (float * int * int) (liste non vide) ; complexité ?

Composantes connexes : on veut un tableau c de taille où c.(i) est l'indice, entre et (nombre de composantes) , de la composante de , la valeur signifiant « pas encore déterminée » ; un sommet est visité si et seulement si c.(i) >= 0. Le sujet donne :


let rec explorer g c k s =
  if c.(s) < 0 then begin
    c.(s) <- k;
    List.iter (fun (v, _) -> explorer g c k v) g.(s)
  end

Q15. Décrire précisément l'effet de explorer g c k s.
Q16. Écrire composantes_connexes : graphe -> int array, en .
Q17. En déduire est_connexe : graphe -> bool.

Corrigé

Q10.


let max_tab a =
  let m = ref a.(0) in
  for i = 1 to Array.length a - 1 do
    m := max !m a.(i)
  done;
  !m

Invariant : au début du tour d'indice , !m est le maximum de a.(0), …, a.(i-1) ; il est vrai pour , et le tour l'étend à l'indice . À la sortie, !m est le maximum du tableau entier. La boucle fait tours dont le corps (un accès, une comparaison, une affectation) est en temps constant : coût . Essais : max_tab [|3; 7; 2|] = 7, max_tab [|-5|] = -5, max_tab [|-3; -1; -8|] = -1.

Q11. Le sommet a deux voisins, (poids ) et (poids ) :


g.(7) = [(0, 18.0); (8, 19.0)]

ou la même liste dans l'autre ordre (l'ordre n'est pas imposé).

Q12. On ajoute l'arête en tête des deux listes, pour respecter la symétrie de la représentation :


let ajoute_arete g (w, i, j) =
  g.(i) <- (j, w) :: g.(i);
  g.(j) <- (i, w) :: g.(j)

Deux accès et deux affectations dans un tableau, deux ajouts en tête de liste : temps constant. Un ajout en queue (g.(i) @ [(j, w)]) coûterait le degré de .

Q13. On parcourt toutes les listes et l'on ne garde un couple de g.(i) que si , ce qui retient chaque arête exactement une fois, sous la forme imposée :


let toutes_les_aretes g =
  let aretes = ref [] in
  for i = 0 to nb_sommets g - 1 do
    List.iter (fun (j, w) -> if i < j then aretes := (w, i, j) :: !aretes) g.(i)
  done;
  !aretes

L'arête apparaît dans g.(i) et dans g.(j) ; le test i < j n'est vrai que pour l'une des deux occurrences. Le tour d'indice coûte (une fonction en temps constant par élément de g.(i)), d'où un coût total . Sur la figure 2, on obtient bien les 17 arêtes de la table liaisons de la partie I.

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, gratuitement

Inscription gratuite en 30 secondes (e-mail, nom d'utilisateur, mot de passe, classe ou profil), sans carte bancaire : arrivée directe sur le corrigé.

Toutes les parties de l'épreuve

Corrigé complet gratuit →