Перерахуйте всі двійкові дерева з n вузлами


10

Враховуючи ціле n, перерахуйте всі можливі повні двійкові дерева з п внутрішніми вузлами. (Повні бінарні дерева мають рівно 2 дитини на кожному внутрішньому вузлі). Структура дерева повинна виводитися як обхід дерева заздалегідь замовленим з 1, що представляє внутрішній вузол, і 0 - зовнішній вузол (Null).

Ось приклади для перших n:

0:
0

1:
100

2:
11000
10100

3:
1110000
1101000
1100100
1011000
1010100

Це кодовий гольф, приз якого отримає найменша кількість персонажів. Дерева повинні виводитись по одному на рядок до stdout. Програма повинна читати n з командного рядка або stdin.


Я думав про цю проблему, коли намагався створити систему письма, що нагадує лабіринт
Мінг-Тан

Який стандартний термін до оголошення рішення?
Кайл Батт

Чи буде якийсь інтерес зробити незначну варіацію цієї проблеми, де потрібно було замовити вихід і потокове передавання?
Кайл Батт

@Kyle Butt Просто моя думка, але я не думаю, що мені було б цікаво. Для мене частина задоволення від цих проблем полягає у спробах альтернативних підходів, і вимагаючи певного порядку, швидше за все, обмежить кількість життєздатних алгоритмів.
migimaru

Відповіді:


3

Perl - 125 79 символів

Кількість включає 4 символи для " -ln" опцій. Бере п від стдін.

Новий конструктивний підхід:

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

Формуйте розв’язок для n, замінивши новий внутрішній вузол ("100") для кожного листа ("0"), у свою чергу, у кожному дереві з розчину для n-1.

(Я зобов'язаний цією концепцією іншим рішенням, які використовують внутрішній вузол для підстановки [100-> 0] підстановки для перевірки послідовно генерованих рядків, і я вважаю, що побачив - написавши свою відповідь на основі цієї концепції - цей самий 0- > 100 способу побудови в чиїйсь проміжному редагуванні.)

Попередній рекурсивний підхід:

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

Рекурсивний незворушний:

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)

Запускається з командного рядка, тобто "php golf.php 1" виводить "100".

EDIT: Виріжте 4 символи альтернативним методом, нарощуючи рядки з 0, а не повторюючи вниз від $ n. Використовує PHP 5.3 для скороченого потрійного оператора; інакше потрібні ще 2 символи.

EDIT 2: збережено ще 4 символи з деякими змінами в циклі.

EDIT 3: Я намагався інший підхід, і я, нарешті, отримав його нижче старого методу.

Всі дерева можна розглядати як двійкові представлення цілих чисел між 4 ^ n (або 0, коли n = 0) і 2 * 4 ^ n. Ця функція проходить цикл через цей діапазон і отримує двійковий рядок кожного числа, а потім повторно зменшує його, замінюючи "100" на "0". Якщо підсумковий рядок "0", то це дійсне дерево, тому виведіть його.

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

Рубі, 99 94 92 89 87 символів

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

Вхід зчитується зі stdin.

> echo 2 | ruby binary_trees.rb
10100
11000

Редагувати 1: Змінено IO (див. Коментарі 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]

Редагувати 2: Змінено алгоритм.

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

Редагування 3: Версія тепер використовує третій підхід (використовуючи ідею migimaru).

Редагування 4: Знову два символи. Дякую migimaru.


Буде на один символ коротше, щоб прийняти вхід від stdin.
Lowjacker

Крім того, вам не потрібно *?\n, тому що putsдрукує кожен елемент масиву у власному рядку.
Lowjacker

@Lowjacker Дякую
Говард

Я щойно почав намагатися вивчити Рубі, але думаю, що ви можете зберегти персонажа, використовуючи 0vremen замість {} в той час, як. Принаймні, це працює в NetBeans.
migimaru

Також суб! тут достатньо замість gsub !, тож це ще один символ, який ви можете зберегти.
migimaru

1

Ruby 1.9 (80) (79)

Використовуючи нерекурсивний, конструктивний підхід, використовуваний DCharness.

EDIT: Збережено 1 символ.

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

0

Haskell 122 символи

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)

Оскільки IO є нетривіальною частиною коду в haskell, можливо, хтось може використати подібне рішення іншою мовою. По суті випадкові прогулянки по квадрату знизу зліва вгору правою зупинкою, якщо діагональ перекреслена. Еквівалентно наступному:

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

Зауважте, що я не маю намір сприймати це як відповідь, просто думав, що кину свою туди.
Кайл Батт

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.