Adloun

Probleme – Biparti si et seulement si aucun cycle impair

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 13 — Le modèle des graphes

Énoncé

Le chapitre ne démontre que le sens direct.

Corrigé

1. La réciproque. Supposons sans cycle impair. Il suffit de traiter une composante connexe, puis de réunir les parties obtenues.

Soit donc connexe, et un sommet quelconque. Notons la distance de à — le nombre minimal d'arêtes d'un chemin de à —, définie pour tout par connexité. Posons

Ces deux ensembles partagent . Montrons que toute arête relie à .

Soit une arête. D'abord : un chemin optimal vers prolongé par l'arête donne un chemin vers , donc , et symétriquement. Il reste à écarter .

Supposons . Prenons un chemin optimal de à et un chemin optimal de à . Le long d'un chemin optimal, la distance croît strictement de à chaque pas : le -ième sommet de est à distance . Soit alors le sommet commun aux deux chemins de plus grande distance — il en existe, étant commun.

Les portions de et de allant de à et de à ne se rencontrent qu'en : un autre sommet commun serait à distance strictement supérieure à , contredisant le choix de . Leurs longueurs valent chacune, un sous-chemin d'un chemin optimal étant optimal, et car entraînerait , donc . En concaténant les deux portions et l'arête , on obtient un cycle de longueur

qui est impair — et c'est bien un cycle, sans répétition d'arête, les deux portions étant disjointes hors de . Contradiction. Donc , d'où et les deux extrémités sont de parités différentes : l'arête relie à .

2. L'algorithme. La démonstration est effective : elle donne la bipartition, se calcule par un parcours en largeur, et la contradiction est un test.


(* Renvoie Some couleur si g est biparti (couleur.(u) vaut 0 ou 1),
   None sinon. n sommets, listes d'adjacence g. Complexité : Theta(n + m). *)
let bicolorer n g =
  let couleur = Array.make n (-1) in
  let biparti = ref true in
  for s = 0 to n - 1 do
    if couleur.(s) = -1 then begin        (* une composante non encore vue *)
      couleur.(s) <- 0;
      let f = Queue.create () in
      Queue.push s f;
      while not (Queue.is_empty f) do
        let u = Queue.pop f in
        List.iter (fun v ->
          if couleur.(v) = -1 then begin
            couleur.(v) <- 1 - couleur.(u);      (* on ALTERNE *)
            Queue.push v f
          end
          else if couleur.(v) = couleur.(u) then biparti := false) g.(u)
      done
    end
  done;
  if !biparti then Some couleur else None

Correction : l'invariant du parcours est couleur.(u) pour tout sommet colorié — vrai à l'initialisation, et conservé puisqu'on colorie chaque nouveau sommet de la couleur opposée à celle de son découvreur, et que le parcours en largeur découvre chaque sommet par un chemin optimal. Le test couleur.(v) = couleur.(u) détecte donc exactement une arête entre deux sommets de même parité, c'est-à-dire, par la démonstration ci-dessus, un cycle impair.

Complexité : chaque sommet est empilé une fois et chaque arête examinée deux fois — une par extrémité —, soit en temps et en mémoire. C'est le coût d'un simple parcours, et il faut le mesurer à l'aune de l'alternative : chercher un cycle impair en énumérant les cycles serait exponentiel. Une caractérisation combinatoire ne donne pas toujours un algorithme ; celle-ci, si, et c'est ce qui la rend précieuse.

3. Ce que l'algorithme rend en cas d'échec. L'arête fautive est un certificat : en remontant les arbres du parcours depuis et depuis jusqu'à leur ancêtre commun, on reconstruit un cycle impair explicite. C'est une qualité qu'il faut exiger d'un algorithme de décision : répondre « non » sans preuve oblige l'utilisateur à faire confiance ; répondre « non, voici pourquoi » se vérifie en .

4. Les mises à l'épreuve. Mesuré, chaque réponse confrontée à une recherche indépendante de cycle impair :

graphebiparti ?cycle impair ?résultat
, le carréouinonparts
, le pentagonenonouiarête fautive
ouinonparts
nonouiarête fautive
arbre à sommetsouinonparts
cube ouinonparts

Les deux colonnes centrales sont toujours opposées : la caractérisation est confirmée sur les six cas. Deux remarques que ce tableau suggère. Tout arbre est biparti — il n'a aucun cycle, donc aucun cycle impair, et la bipartition est le partage par la parité de la profondeur. Et les cycles pairs , , … sont bipartis tandis que , , … ne le sont pas : ce sont les exemples minimaux des deux côtés.

À quoi cela sert. La bipartition est le modèle de tout appariement : étudiants et stages, tâches et machines, offres et demandes. Savoir en si un graphe est biparti, c'est savoir si le problème d'appariement s'y pose — et le programme cite la bicolorabilité au chapitre chap:parcours précisément à ce titre.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.