Perl, 65 59 55 54 байт
Включає +2 для -ap
Запустити з розміром дерева на STDIN:
for i in `seq 24`; do echo -n "$i: "; vines.pl <<< $i; echo; done
vines.pl
:
#!/usr/bin/perl -ap
$_=map{${"-@F"%$_}|=$_=$$_|$"x$p++.1;/.\b/g}1-$_..-1
Пояснення
Якщо переписати дерево
3
|
2 4
\ /
1
|
0
до того, де кожен вузол містить набір усіх своїх предків і себе:
{3}
|
{2,3} {4}
\ /
\ /
{1,2,3,4}
|
{0,1,2,3,4}
Тоді ми можемо описати, наприклад, всі вузли шлях від 4 до 3 як:
- Усі вузли, які містять 3, але не 4 (йде від 3)
- Усі вузли, що містять 4, але не 3 (йде від 4)
- Найвищий вузол, який містить 3 і 4 (з'єднання)
Кількість ребер на один менше, ніж кількість вузлів, тому ми можемо використовувати це для ігнорування точки з'єднання, тому кількість ребер на шляху від 4 до 3 дорівнює 3, оскільки:
- Кількість вузлів, які містять 3, але не 4: 2 вузли
- Кількість вузлів, які містять 4, але не 3: 1 вузол
Зауважте, що це також працює для шляху, який безпосередньо спускається до своєї цілі, наприклад, для шляху від 3 до 2 кількість ребер дорівнює 1, оскільки:
- Кількість вузлів, які містять 2, але не 3: 0 вузли
- Кількість вузлів, які містять 3, але не 2: 1 вузол
Тоді ми можемо підсумовувати всі ці комбінації.
Якщо ви замість цього подивитесь лише на вузол, наприклад, вузол 2 із набором предків {2,3}
. Цей вузол збирається зробити один раз при обробці шляху, 2 to 1
оскільки він містить 2, але не 1. Він нічого не зробить для шляху, 3 to 2
оскільки у нього є і 2, і 3, але він зробить один раз при обробці шляху, 4 to 3
оскільки у нього є 3, але немає 4. Загалом, число у наборі предків вузла вносить по одному для кожного сусіда (одного нижчого від вищого), якого немає в наборі. За винятком максимального елемента (4 у цьому випадку), який сприяє лише низькому сусіду 3, оскільки шляху немає5 to 4
. Simula 0 є одностороннім, але оскільки 0 завжди знаходиться в корені дерева і містить усі числа (це кінцеве з'єднання, і ми не рахуємо приєднання), жодного внеску з 0 не існує, тому найпростіше просто залишити вузол 0 взагалі.
Тож ми також можемо вирішити проблему, подивившись набір предків для кожного вузла, підрахувавши внески та суму за всіма вузлами.
Щоб легко обробити сусідів, я буду представляти набори предків як рядок пробілів і 1, де кожен 1 у положенні p являє собою, що n-1-p є предком. Так, наприклад, у нашому випадку n=5
1 у положенні 0 вказує, що 4 є предком. Я залишу пробіли. Отже, власне зображення дерева, яке я буду буду:
" 1"
|
" 11" "1"
\ /
\ /
"1111"
Зауважте, що я залишив вузол 0, який буде представлений через те, "11111"
що я ігнорую вузол 0 (він ніколи не сприяє).
Предки без нижнього сусіда тепер представлені кінцем послідовності 1-х. Предки, які не мають вищого сусіда, тепер представлені початком послідовності 1, але ми повинні ігнорувати будь-який початок послідовності на початку рядка, оскільки це буде представляти шлях, 5 to 4
який не існує. Ця комбінація точно відповідає регексу /.\b/
.
Побудова рядків предків виконується обробкою всіх вузлів у порядку, n-1 .. 1
і встановлюють 1 у положенні для самого вузла і роблять "чи" у нащадка.
З усім, що програма досить зрозуміла:
-ap read STDIN into $_ and @F
map{ }1-$_..-1 Process from n-1 to 1,
but use the negative
values so we can use a
perl sequence.
I will keep the current
ancestor for node $i in
global ${-$i} (another
reason to use negative
values since $1, $2 etc.
are read-only
$$_|$"x$p++.1 "Or" the current node
position into its ancestor
accumulator
$_= Assign the ancestor string
to $_. This will overwrite
the current counter value
but that has no influence
on the following counter
values
${"-@F"%$_}|= Merge the current node
ancestor string into the
successor
Notice that because this
is an |= the index
calculation was done
before the assignment
to $_ so $_ is still -i.
-n % -i = - (n % i), so
this is indeed the proper
index
/.\b/g As explained above this
gives the list of missing
higher and lower neighbours
but skips the start
$_= A map in scalar context
counts the number of
elements, so this assigns
the grand total to $_.
The -p implicitly prints
Зауважте, що заміна /.\b/
на /\b/
вирішує цю проблему з версією цієї проблеми, коли тарзан також стоїть на шляху0 to n-1
Деякі приклади того, як виглядають рядки предків (наводяться в порядку n-1 .. 1
):
n=23:
1
1
1
1
1
1
1
1
1
1
1
11
1 1
1 1
1 1
11 11
1 1
11 1 1 11
1 1
1111 11 11 1111
111111111 111111111
1111111111111111111111
edges=68
n=24:
1
1
1
1
1
1
1
1
1
1
1
1
1 1
1 1
1 1
1 1
1 1
1 1 1 1
1 1
11 1 1 11
1 1 1 1
1 1 1 1
1 1
edges=82