Enumera tutti gli alberi binari con n nodi


10

Dato un numero intero n, enumera tutti i possibili alberi binari completi con n nodi interni. (Gli alberi binari completi hanno esattamente 2 figli su ogni nodo interno). La struttura ad albero dovrebbe essere prodotta come un attraversamento pre-ordine dell'albero con 1 che rappresenta un nodo interno e 0 che rappresenta un nodo esterno (Null).

Ecco alcuni esempi per i primi n:

0:
0

1:
100

2:
11000
10100

3:
1110000
1101000
1100100
1011000
1010100

Questo è un codice golf con il premio che va al minor numero di personaggi. Gli alberi dovrebbero essere inviati uno per riga allo stdout. Il programma dovrebbe leggere n dalla riga di comando o stdin.


Stavo pensando a quel problema quando stavo cercando di creare un sistema di scrittura simile a un labirinto
Ming-Tang,

Qual è la scadenza standard prima di dichiarare una soluzione?
Kyle Butt,

Ci sarebbe interesse a fare una leggera variazione di questo problema, in cui era necessario ordinare l'output e lo streaming?
Kyle Butt,

@Kyle Butt Solo la mia opinione, ma non credo che sarei interessato. Per me, parte del divertimento con questi problemi sta provando approcci alternativi e richiedere un certo ordine probabilmente limiterebbe il numero di algoritmi praticabili.
migimaru,

Risposte:


3

Perl - 125 79 caratteri

Il conteggio include 4 caratteri per " -ln" opzioni. Prende n da stdin.

Nuovo approccio costruttivo:

@a=0;map{%a=();map{$a{"$`100$'"}=1while/0/g;}@a;@a=keys%a}1..$_;print for@a

Forma la soluzione per n sostituendo un nuovo nodo interno ("100") per ogni foglia ("0"), a sua volta, in ciascun albero dalla soluzione per n-1.

(Devo questo concetto alle soluzioni di altri che usano il nodo interno per sfogliare la sostituzione [100-> 0] per la verifica di stringhe generate in sequenza, e credo di aver visto - dopo aver scritto la mia risposta basata su quel concetto - lo stesso 0- > 100 metodo di costruzione nella modifica intermedia di qualcuno.)

Approccio ricorsivo precedente:

sub t{my$n=shift;if($n){--$n;for$R(0..$n){for$r(t($R)){for$l(t($n-$R)){push@_,"1$l$r"}}}}else{push@_,"0"}@_}print for t$_

Non ricorsivo non golfato:

sub tree {
  my ($n) = @_;
  my @result = ();
  if ( $n ) {
    for $right_count ( 0 .. $n-1 ) {
      for $right ( tree( $right_count ) ) {
        for $left ( tree( ($n-1) - $right_count ) ) {
          push @result, "1$left$right";
        }
      }
    }
  }
  else {
    push @result, "0";
  }
  return @result;
}
foreach $tree ( tree($_) ) {
  print $tree;
}

2

PHP (142) (138) (134) (113)

Viene eseguito dalla riga di comando, ovvero "php golf.php 1" genera "100".

EDIT: taglia 4 caratteri con un metodo alternativo, costruendo le stringhe da 0 invece di ricorrere da $ n. Utilizza PHP 5.3 per l'operatore ternario abbreviato; in caso contrario, sono necessari altri 2 caratteri.

EDIT 2: Hai salvato altri 4 personaggi con alcune modifiche ai loop.

EDIT 3: stavo provando un approccio diverso e finalmente l'ho ottenuto sotto il vecchio metodo.

Tutti gli alberi possono essere considerati come rappresentazioni binarie di numeri interi compresi tra 4 ^ n (o 0, quando n = 0) e 2 * 4 ^ n. Questa funzione scorre attraverso quell'intervallo e ottiene la stringa binaria di ciascun numero, quindi la riduce ripetutamente sostituendo "100" con "0". Se la stringa finale è "0", allora è un albero valido, quindi emettilo.

for($i=$p=pow(4,$argv[1])-1;$i<=2*$p;){$s=$d=decbin($i++);while($o!=$s=str_replace(100,0,$o=$s));echo$s?:"$d\n";}

2

Rubino, 99 94 92 89 87 caratteri

(n=4**gets.to_i).times{|i|s=(n+i-1).to_s 2;t=s*1;0while s.sub!'100',?0;puts t if s==?0}

L'input viene letto dallo stdin.

> echo 2 | ruby binary_trees.rb
10100
11000

Modifica 1: IO modificato (vedere i commenti di Lowjacker)

b=->n{n==0?[?0]:(k=[];n.times{|z|b[z].product(b[n-1-z]){|l|k<<=?1+l*''}};k)}
puts b[gets.to_i]

Modifica 2: algoritmo modificato.

b=->n{n==0?[?0]:(k=[];b[n-1].map{|s|s.gsub(/0/){k<<=$`+'100'+$'}};k.uniq)}
puts b[gets.to_i]

Modifica 3: la versione ora utilizza il terzo approccio (usando l'idea di migimaru).

Modifica 4: Ancora due personaggi. Grazie a Miguel.


Sarebbe un carattere più breve per accettare l'input da stdin.
Lowjacker

Inoltre, non è necessario *?\n, poiché putsstampa ogni elemento dell'array su una propria riga.
Lowjacker

@Lowjacker Grazie.
Howard,

Ho appena iniziato a provare a imparare Ruby, ma penso che puoi salvare un personaggio usando 0while invece di {} while. Almeno funziona in NetBeans.
migimaru,

Inoltre, sub! è sufficiente qui invece di gsub !, quindi è un altro personaggio che potresti salvare.
migimaru,

1

Ruby 1.9 (80) (79)

Utilizzando l'approccio non ricorsivo e costruttivo utilizzato da DCharness.

EDIT: 1 carattere salvato.

s=*?0;gets.to_i.times{s.map!{|x|x.gsub(?0).map{$`+'100'+$'}}.flatten!}
puts s&s

0

Haskell 122 caratteri

main=do n<-readLn;mapM putStrLn$g n n
g 0 0=[['0']]
g u r|r<u||u<0=[]
g u r=do s<-[1,0];map((toEnum$s+48):)$g(u-s)(r-1+s)

Dato che l'IO è una parte non banale del codice in haskell, forse qualcuno può usare una soluzione simile in un'altra lingua. Camminate essenzialmente casuali in un quadrato dall'angolo in basso a sinistra all'angolo in alto a destra fermandosi se la diagonale è incrociata. Equivalente a quanto segue:

module BinTreeEnum where

import Data.List
import Data.Monoid

data TStruct = NonEmpty | Empty deriving (Enum, Show)
type TreeDef = [TStruct]

printTStruct :: TStruct -> Char
printTStruct NonEmpty = '1'
printTStruct Empty = '0'

printTreeDef :: TreeDef -> String
printTreeDef = map printTStruct

enumBinTrees :: Int -> [TreeDef]
enumBinTrees n = enumBinTrees' n n where
  enumBinTrees' ups rights | rights < ups = mempty
  enumBinTrees' 0   rights = return (replicate (rights+1) Empty)
  enumBinTrees' ups rights = do
    step <- enumFrom (toEnum 0)
    let suffixes =
          case step of
            NonEmpty -> enumBinTrees' (ups - 1) rights
            Empty -> enumBinTrees' ups (rights - 1)
    suffix <- suffixes
    return (step:suffix)

mainExample = do
  print $ map printTreeDef $ enumBinTrees 4

Nota che non intendo accettare questa come risposta, ho solo pensato di buttare la mia là fuori.
Kyle Butt,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.