Enumere todas as árvores binárias com n nós


10

Dado um número inteiro n, enumere todas as possíveis árvores binárias completas com n nós internos. (Árvores binárias completas têm exatamente 2 filhos em cada nó interno). A estrutura da árvore deve ser gerada como uma travessia de pré-ordem da árvore, com 1 representando um nó interno e 0 representando um nó externo (Nulo).

Aqui estão alguns exemplos para os primeiros n:

0:
0

1:
100

2:
11000
10100

3:
1110000
1101000
1100100
1011000
1010100

Este é um código de golfe com o prêmio indo para o menor número de caracteres. As árvores devem ser produzidas uma por linha para stdout. O programa deve ler n na linha de comando ou stdin.


Eu estava pensando sobre esse problema quando eu estava tentando fazer um labirinto escrita sistema
Ming-Tang

Qual é o prazo padrão antes de declarar uma solução?
Kyle Butt

Haveria algum interesse em fazer uma ligeira variação desse problema, onde era necessário solicitar a saída e fazer o streaming?
Kyle Bundas

@ Kyle Butt Apenas minha opinião, mas acho que não estaria interessado. Para mim, parte da diversão com esses problemas é tentar abordagens alternativas, e exigir uma certa ordem provavelmente limitaria o número de algoritmos viáveis.
Migimaru

Respostas:


3

Perl - 125 79 caracteres

A contagem inclui 4 caracteres para as -lnopções " ". Toma n de stdin.

Nova abordagem construtiva:

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

Forme a solução para n substituindo um novo nó interno ("100") para cada folha ("0"), por sua vez, em cada árvore da solução para n-1.

(Devo esse conceito às soluções de outros que usam o nó interno para substituir [100-> 0] a folha para verificar seqüências geradas seqüencialmente, e acredito que vi - depois de escrever minha resposta com base nesse conceito - esse mesmo 0- > 100 método de construção na edição intermediária de alguém.)

Abordagem recursiva anterior:

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$_

Recursivo não destruído:

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)

É executado a partir da linha de comando, ou seja, "php golf.php 1" gera "100".

EDIT: Corte 4 caracteres com um método alternativo, construindo as strings a partir de 0 em vez de retornando a partir de $ n. Usa PHP 5.3 para o operador ternário reduzido; caso contrário, são necessários mais 2 caracteres.

EDIT 2: salvou mais 4 caracteres com algumas alterações nos loops.

EDIÇÃO 3: Eu estava tentando uma abordagem diferente e finalmente a obtive abaixo do método antigo.

Todas as árvores podem ser consideradas representações binárias de números inteiros entre 4 ^ n (ou 0, quando n = 0) e 2 * 4 ^ n. Essa função percorre esse intervalo e obtém a sequência binária de cada número e a reduz repetidamente, substituindo "100" por "0". Se a sequência final for "0", é uma árvore válida, portanto, faça a saída.

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

Ruby, 99 94 92 89 87 caracteres

(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}

A entrada é lida a partir de stdin.

> echo 2 | ruby binary_trees.rb
10100
11000

Editar 1: E / S alteradas (consulte os comentários do 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]

Editar 2: algoritmo alterado.

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

Edit 3: A versão agora segue a terceira abordagem (usando a idéia de migimaru).

Editar 4: Novamente dois caracteres. Obrigado a migimaru.


Seria um caractere mais curto para aceitar a entrada de stdin.
Lowjacker 13/08/11

Além disso, você não precisa do *?\n, porque putsimprime cada elemento da matriz em sua própria linha.
Lowjacker

@ Lowjacker Obrigado.
Howard Howard

Comecei a tentar aprender Ruby, mas acho que você pode salvar um personagem usando 0 while em vez de {} while. Pelo menos, funciona no NetBeans.
migimaru 13/08/11

Além disso, sub! é suficiente aqui em vez de gsub !, então esse é outro personagem que você pode salvar.
migimaru

1

Rubi 1.9 (80) (79)

Usando a abordagem construtiva não recursiva usada pelo DCharness.

EDIT: salvou 1 caractere.

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

0

Haskell 122 chars

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)

Como o IO é uma parte não trivial do código em haskell, talvez alguém possa usar uma solução semelhante em outro idioma. Passeios essencialmente aleatórios em um quadrado do canto inferior esquerdo para o canto superior direito, se a diagonal for cruzada. Equivalente ao seguinte:

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

Note que não pretendo aceitar isso como resposta, apenas pensei em jogar o meu por aí.
Kyle Bundas

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.