Aller au contenu

Enraciner un arbre donné par un graphe

🏷️ On considère ici des arbres étiquetés non ordonnés.

Dans cet exercice les étiquettes sont les entiers de 1 à \(n\), la taille du graphe qui est aussi un arbre.

👍 À retenir :

  • Une étiquette peut donc servir de clé de dictionnaire pour identifier un sommet.
  • None peut servir à désigner le parent de la racine... qui n'existe pas !

Construire un arbre enraciné à partir d'un graphe

Un graphe est donné par un dictionnaire d'adjacences :

  • Les clés de ce dictionnaire sont les étiquettes des sommets du graphe.

  • La valeur associée à une clé est la liste des sommets adjacents à la clé, dans un ordre quelconque.

Tous les graphes ne sont pas des arbres

On rappelle qu'un arbre est un graphe, à la fois

  • acyclique : il n'y a pas de cycle dans un arbre.
  • connexe : un arbre est d'un seul morceau.

Dans cet exercice, tous les graphes donnés en paramètre sont des arbres, et il est inutile de le vérifier. Sur le chapitre sur les graphes, il y aura des exercices pour vérifier si un graphe est bien un arbre ; ce seront des algorithmes sur les graphes...

Un exemple simple

Le dictionnaire d'adjacences en Python graphe = {1: [2, 3], 2: [1], 3: [1]} représente le graphe suivant, qui est non enraciné.

graph LR
    3("3") --- 1("1")
    1 --- 2("2")

Si on souhaite l'enraciner en 1, on obtient l'unique arbre enraciné non ordonné suivant que l'on peut dessiner de deux manières :

flowchart TB
    subgraph "Dessin 2"
    direction TB
    A("1")-->B("3")
    A("1")-->C("2")
    end
    subgraph "Dessin 1 "
    direction TB
    E("1")-->F("2")
    E("1")-->G("3")
    end

Chacune des deux réponses suivantes sont donc acceptées.

🐍 Script Python
[1, [[2, []], [3, []]]]

[1, [[3, []], [2, []]]]

Ce qui explique le dernier test public

🐍 Script Python
graphe = {1: [2, 3], 2: [1], 3: [1]}

arbre = enracine(graphe, 1)

assert (
    arbre == [1, [[2, []], [3, []]]]
) or (
    arbre == [1, [[3, []], [2, []]]]
)

Les tests privés utiliseront la fonction sont_similaires qu'il est conseillé de construire avant.

Exercice

Coder une fonction enracine qui prend un graphe et une racine en paramètres et qui renvoie un arbre étiqueté associé au graphe et à la racine désignée.

Un tel arbre théorique est non ordonné, ainsi la liste des enfants pourra être donnée dans n'importe quel ordre. Les tests accepteront toute variation.

Indice

On pourra compléter le code suivant :

🐍 Script Python
def enracine(graphe, racine):
    "Renvoie un arbre enraciné issu de racine à partir de graphe"

    # fonction intérieure récursive
    def construit(racine, parent):
        """Renvoie l'arbre associé à graphe dont
         la racine et son parent sont donnés
        """
        enfants = []
        for sommet in graphe[racine]:
            if ...:
                enfants.append(...)
        return [racine, enfants]

    # La racine n'a pas de parent
    return construit(racine, None)
###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : /
.128013],59/f.q!78r;nb N_o=ylaepcwgu)vd4613kRméhtsP(S0à2[i:050G0y0Q0x0Z0w0R0q0A0w0x0R0R0u010Q0Z0z010406050R0D0N0N0x0m0v040U0t0w0D0^0t0o0q020x0N0z0n0q0M0y120m0i0D0y0R050f0 1113150}0z04051A1t1D0f1A0}0G0Z0F0-0/0;0?0P0Z0C0P0w1R0P0Q0{050(0p0w0y1M0:0=011Q1S1U1S0Q1!1$1Y0Q0m1B0Q0P1(1O010g0*0y0o1g0y010-180R0z0x0o0?0X1Y282a1|1*1 1$220N24040a0q0S0m0t0z0t0R0Z1b1d0$260m0m0y0A2y1t2f0o1B0f1`2K1@1_1^1Z0G2h0?1U0o212v1Y1J1L0.1)2U0Z2W0o0t2!1Y0z2D1B2I2K2=0~291d2$1}2+0m120w0{0q0J2H2_0|2^2g2{1*2}2 310X342a362I2T013b0x30040q0K3f2J0}3i390?3l3n0q0H3r3h2_3j3x310d3B3t3D3v3k0t2~3m310I3I372`1N3a3N3c3o0k3S3u3V3w3X3P3o0l3#3K3%3M3O3y0e3-383/3F040J0V3@3U2%3:3Y0J331u353J3^403`0J3e453g473 2|3)3n0J3q4d3s3T3E4i0{0J3A4m3C484h3;4r3H4u1E2:1t2!2N0G1_2S3L0A2,2n0#1K1B2/0y2;353B054L0$4T4w1*0L0{0$0g4V3$400B314*3.490g0{210m0x0A2)0y4/4!0?0`040T4}4g3a0{0C4^0z0P4|4B4+1}500c3B0q4o3L0o0{4^4`2W533j500E0!3I0q5w5i5d1*0R2d04011l0o0F0t0Z1%0D1d130p2D0q4@4_2)0O0q0Z0;0D0q2A5n4{0q0W0q290m0^0m5Z1%570x59243I065x5y4:1}0A0J0{030q0g1c2F0Z1c5V0o0Q0O0m5J0D5P0m0O0A6d2w0F5b2=5^5x5j3/4$044(5q3L4-3o6u3_4=044L0o0R1@0D2x6y4050525c5{55045#5p6M4~015f5h6p490{5*210Q6I5e0{5t3~3j6w5_5_6%5A0G0{016@5F5H5J0q0w005N5P1)0t4`5U5(5:5=5Z1c6$4u4f3j0R6=3o6.7h0/0q6Q1%0%0q0R666!687o79780o0o0O1s7b6X1}7e317h0q6@015v7F7B6O210g2a0Q7z2=5`6T0t0{0u6W5z4 0{0Y0b7J7h7L0?6r620m7Y6N3w0{7p110%7/7U6w2)7_547;04765a6:7!040Y833k5m5S6R2@7Z6U0{0b5u7b7F6.7*016r0Z4)4u7T7~88047?2m7a7S8l7V040j7X8q8l5l047r8x4U8d508h6m8j8j8F4?0o7O687R8K7:018A0h878G5;0z210G876K8$0{6C6E0m6G8J3g8l8-6S8s8G8v7^8{5r0{5g8E8d8G7l8,6)0E7(8k8d6r2D0Q6d0o7}91858.6P8a6l8X6T6V948Y8G7N7P8W8^8L8f5@6/9d5m0%9h9j5k8/1c8;8?98519m97903L9s8y9d0A0{0r1c9p9z8Y5s3S0f4X4S4C9,0f4F1t0Q4H9;2Q2L0x1#9.4F1z4Z8s2D0N0s7O0L0y0s0P0K0{1l1n1p1r0q8N4U1G360$0(0*0,3L0G2a0C0y0m0{3t101n1517192y5Q1d5L1%1.2W0c7o0Q0v1$61632y2W0w2Haw1xaj1K3j1,1T1V1X9 3j2j21230{2p0U0A6b0z0Q2q0v1`1c4V4R9 2?4U9+a$3L6r6t9S3/6-8$6A5R5o9#2J8_0{6L8c9u565882b36J929I3_89b99O6*8i6o8d5B6?6_5I5K5M0m5O7m0o6Q5U5W0 5.7k9o5%5)135,bK815?7b6n5w8l5}5 aN0o64662)696b0y6d1%6f6h0m6jba0|9D8Yb10y8pbf6Tb5bk2|6A8:6F6Hb 1*8`b|8|bp4{9O939Vbg8H136#brag4e8l6-7Kc50?7D5D6^216`aF6~bC700;720Z740qbS7v8@4nbv7f8P5x7j7l5Qa;7p1d8I7t7s0G1c7x9ycI8Ycr8j7H9bb@6T9e9G0m9i9t9r7#9Q9occbnbl9lbtcL8R6B9Lc3cHa 3/c79qc98u0t7@d2bc04cd358r3Eca8bd69k9ac:8s7,3Nc_2|7=d98wdr1*0t7{c/ce6T8GbS9O86cp8t9Rc89k7%dn3j8nb{dfc~8~d2dg3L8A8Cdw7 8Ic)bu9%8fdM6m06bVdV6q9F9gc.dZ8tc28=c4dK9Tbdc?bqdH9UdR9W9Y9!br9)a~9-2K9}4E0%0)0+369/edam04.