Arbres binaires
Un arbre binaire est un arbre avec des nœuds de trois types:
- nœuds terminaux, qui n'ont pas d'enfants
- nœuds unaires, qui ont chacun un enfant
- nœuds binaires, qui ont chacun deux enfants
Nous pouvons les représenter avec la grammaire suivante, donnée en BNF (forme Backus – Naur):
<e> ::=
<terminal>
| <unary>
| <binary>
<terminal> ::=
"0"
<unary> ::=
"(1" <e> ")"
<binary> ::=
"(2" <e> " " <e> ")"
Dans cette grammaire, les nœuds sont donnés en précommande et chaque nœud est représenté par un chiffre qui est le nombre d'enfants qu'il a.
Numéros Motzkin
Les nombres de Motzkin ( OEIS ) ( Wikipedia ) ont de nombreuses interprétations, mais une interprétation est que le n
nombre de Motzkin est le nombre d'arbres binaires distincts avec des n
nœuds. Un tableau des nombres Motzkin commence
N Motzkin number M(N)
1 1
2 1
3 2
4 4
5 9
6 21
7 51
8 127
...
par exemple, M(5)
est 9, et les neuf arbres binaires distincts avec 5 nœuds sont
1 (1 (1 (1 (1 0))))
2 (1 (1 (2 0 0)))
3 (1 (2 0 (1 0)))
4 (1 (2 (1 0) 0))
5 (2 0 (1 (1 0)))
6 (2 0 (2 0 0))
7 (2 (1 0) (1 0))
8 (2 (1 (1 0)) 0)
9 (2 (2 0 0) 0)
Tâche
Prenez un seul entier positif n
en entrée et sortez tous les arbres binaires distincts avec des n
nœuds.
Exemples n
de 1 à 5 avec parenthèses incluses pour plus de lisibilité
0
(1 0)
(1 (1 0))
(2 0 0)
(1 (1 (1 0)))
(1 (2 0 0))
(2 0 (1 0))
(2 (1 0) 0)
(1 (1 (1 (1 0))))
(1 (1 (2 0 0)))
(1 (2 0 (1 0)))
(1 (2 (1 0) 0))
(2 0 (1 (1 0)))
(2 0 (2 0 0))
(2 (1 0) (1 0))
(2 (1 (1 0)) 0)
(2 (2 0 0) 0)
Contribution
L'entrée sera un entier positif.
Production
La sortie doit être une représentation intelligible des arbres binaires distincts avec autant de nœuds. Il n'est pas obligatoire d'utiliser la chaîne exacte donnée par la grammaire BNF ci-dessus: il suffit que la syntaxe utilisée donne une représentation non ambiguë des arbres. Par exemple, vous pouvez utiliser []
au lieu de ()
, un niveau supplémentaire de crochets [[]]
au lieu de[]
, des parenthèses externes sont présentes ou manquantes, des virgules supplémentaires ou aucune virgule, des espaces supplémentaires, des parenthèses ou aucune parenthèse, etc.
Tous ces éléments sont équivalents:
(1 (2 (1 0) 0))
[1 [2 [1 0] 0]]
1 2 1 0 0
12100
(1 [2 (1 0) 0])
.:.--
*%*55
(- (+ (- 1) 1))
-+-11
Également une variation proposée par @xnor dans un commentaire. Puisqu'il existe un moyen de traduire cela dans un format qui peut être compris, il est acceptable.
[[[]][]] is (2 (1 0) 0)
Pour rendre cela plus facile à comprendre convertir certains des []
à ()
comme si
[([])()]
Maintenant, si vous commencez par
[]
puis insérez un binaire qui a besoin de deux expressions que vous obtenez
[()()] which is 2
puis pour le premier () insérer un unaire qui a besoin d'une expression que vous obtenez
[([])()] which is 21
mais puisque []
ou ()
sans crochets intérieurs peut représenter 0 qui n'a plus besoin d'expressions, vous pouvez l'interpréter comme
2100
Notez que les réponses devraient fonctionner théoriquement avec une mémoire infinie, mais manqueront évidemment de mémoire pour une entrée finie dépendante de l'implémentation.
Variations de sortie
BNF xnor Christian Ben
b(t, b(t, t)) [{}{{}{}}] (0(00)) (1, -1, 1, -1)
b(t, u(u(t))) [{}{(())}] (0((0))) (1, -1, 0, 0)
b(u(t), u(t)) [{()}{()}] ((0)(0)) (1, 0, -1, 0)
b(b(t, t), t) [{{}{}}{}] ((00)0) (1, 1, -1, -1)
b(u(u(t)), t) [{(())}{}] (((0))0) (1, 0, 0, -1)
u(b(t, u(t))) [({}{()})] ((0(0))) (0, 1, -1, 0)
u(b(u(t), t)) [({()}{})] (((0)0)) (0, 1, 0, -1)
u(u(b(t, t))) [(({}{}))] (((00))) (0, 0, 1, -1)
u(u(u(u(t)))) [(((())))] ((((0)))) (0, 0, 0, 0)
Un endroit possible pour vérifier les arbres en double
Un endroit pour vérifier un doublon est avec M (5).
Cet arbre a été généré deux fois pour M (5) à partir de M (4) arbres
(2 (1 0) (1 0))
le premier en ajoutant une branche unaire à
(2 (1 0) 0)
et deuxièmement en ajoutant une branche unaire à
(2 0 (1 0))
Comprendre BNF
La BNF est composée de règles simples:
<symbol> ::= expression
où à gauche se trouve un nom de symbole entouré <>
.
À droite, l'expression de construction du symbole. Certaines règles utilisent d'autres règles dans la construction, par exemple
<e> ::= <terminal>
e
peut être un terminal
et certaines règles ont des caractères qui sont utilisés dans la construction du symbole, par exemple
<terminal> ::= "0"
terminal
est juste le caractère zéro.
Certaines règles ont plusieurs façons de les construire, par exemple
<e> ::=
<terminal>
| <unary>
| <binary>
Un e
peut être un <terminal>
ou un <unary>
ou un <binary>
.
Et certaines règles sont une séquence de parties, par exemple
<unary> ::= "(1" <e> ")"
A unary
est les caractères (1
suivis de ce qui peut être construit pour e
suivi de )
.
Vous commencez toujours par la règle de départ, qui pour cela <e>
.
Quelques exemples simples:
La séquence la plus simple est juste 0
. Nous commençons donc avec la règle de départ <e>
et voyons qu'il y a trois choix:
<terminal>
| <unary>
| <binary>
alors prenez le premier <terminal>
. Maintenant, un terminal n'a pas le choix et l'est 0
. Remplacez donc <terminal>
par 0
dans la <e>
règle et vous avez terminé.
Ensuite, le suivant est (1 0)
. Commencez avec <e>
et utilisez la règle <unary>
qui a
"(1" <e> ")"
Maintenant, cela nécessite un <e>
donc nous revenons à <e>
et faisons un choix de l'un des trois, cette fois en choisissant, <terminal>
ce qui donne 0
. Le remplacement 0
en (1 <e> )
donne (1 0)
, et il est remplacé en <unary>
si <e>
est (1 0)
.
la source
Réponses:
Haskell, 68 octets
Les nœuds terminaux sont représentés par
0
, les nœuds unaires et binaires par(e)
resp.(ee)
, donc les deux arbres à trois nœuds sont donnés comme(00)
et((0))
.Exemples:
la source
CJam (37 octets)
Démo en ligne . Notez que ce n'est pas très efficace et que vous ne voulez probablement pas essayer de calculer l'entrée en
5
ligne.Dissection à suivre.
la source
Pyth (
242119 octets)Ceci est basé sur ma solution Python 3 .
C'est ma première utilisation de Pyth, donc c'est probablement encore jouable au golf.
Exemple , sortie lorsque l'entrée est
4
:1 représente un nœud binaire, 0 représente un nœud unaire et -1 représente un nœud terminal. Il y a un nœud terminal implicite à la fin de chaque arbre.
Explication :
la source
brainfuck, 107 octets
Formaté:
Essayez-le en ligne
L'entrée est prise comme un octet et l'arborescence
12100
est représentée comme\x01\x02\x03\x02
suit: pour convertir en arrière, traduiretr/\x01\x02\x03/012/
, inverser la chaîne et ajouter une finale0
. Les arbres sont séparés par\xfe
. (La sortie peut être rendue plus facile à lire en changeant par exemple le premier-
en-36
et le.
en+47.-47
, où-36
signifie une chaîne de 36-
caractères, etc.)Cette approche utilise la propriété (que Ben Frankel a également utilisée): en considérant les nœuds possibles comme
-1, 0, 1
et sans tenir compte du-1
nœud final , une liste représente un arbre valide si et seulement si (1) tous les préfixes de la liste ont une somme non négative, et (2) la somme de la liste entière est égale à0
. La première condition est conservée lors de la génération de nœuds intermédiaires, donc seule la deuxième condition doit être vérifiée à la fin.La bande est divisée en cellules à 5 nœuds,
où
i
est l'indice (descendant de gauche à droite),d
est la somme partielle etx
est l'élément.Croquis du flux de contrôle:
Notez que parfois une valeur est stockée ou initialisée comme étant un ou deux supérieure à la valeur réelle (conceptuelle) et ajustée selon les besoins.
la source
Python 3 (
138134128 128121119 octets)Exemple de sortie, pour
n=5
:1 représente un nœud binaire, 0 représente un nœud unaire et -1 représente un nœud terminal. Il y a un nœud terminal implicite à la fin de chaque arbre.
Le programme commence à prendre trop de temps aux alentours
n=17
.la source
JavaScript (Firefox 30-57), 79 octets
Où
-1
représente un terminal,0
un nœud unaire et1
un nœud binaire. Commence à ralentirm=14
sur mon PC. Fonctionne récursivement depuis la fin de l'arborescence.l
est limité par le fait qu'il ne peut rester qu'un seul nœud à la fin.n
est limité par la nécessité d'avoir suffisamment de nœuds non comptabilisés pour être ses enfants.la source
Prolog,
149144138137 137131107 octetsEt pour compter les solutions
la source
Python, 71 octets
Cela représente les arbres comme des tuples imbriqués tels que
((((),), ()),)
, qui peuvent être transformés en((())())
en supprimant les virgules, les espaces et les éléments les plus externes()
.Une version antérieure de 76 octets:
la source
CJam, 38 octets
Utilise une approche différente à laquelle répond CJam de Peter Taylor.
La sortie sera quelque chose comme
1110120020102100
. Chaque arbre est un groupe den
chiffres (oùn
est le numéro d'entrée).L'idée de base est que nous générons chaque chaîne de chiffres possible
0
,1
et2
, puis filtrer seulement ceux qui sont des arbres bien formés.la source