Порахуйте дерева


11

Дерево є зв'язковою, неорієнтований граф без циклів. Ваше завдання - порахувати, скільки існує різних дерев із заданою кількістю вершин.

Два дерева вважаються виразними, якщо вони не є ізоморфними . Два графіки є ізоморфними, якщо їх відповідні вершини можна з'єднати таким чином, що в одному графі є край між двома вершинами, якщо і лише якщо є край між вершинами, сполученими з цими вершинами в іншому графіку. Для більш повного опису дивіться посилання вище.

Щоб побачити, як виглядають усі окремі дерева розмірів від 1 до 6, подивіться тут .

Серія, яку ви намагаєтеся вивести, - A000055 в OEIS.

Обмеження : ваше рішення повинно зайняти протягом декількох хвилин або менше для входу 6. Це не призначене для усунення експоненціальних алгоритмів часу, але призначене для усунення подвійно-експоненціальних алгоритмів часу, таких як жорстоке примушування по всіх наборах ребер.

Введення: Будь-яке невід'ємне ціле число.

Введення даних може бути будь-яким стандартним способом, включаючи STDIN, параметр командного рядка, введення функції тощо.

Вихід: кількість різних дерев з такою ж кількістю вершин, як і вхід.

Вихід може бути будь-яким стандартним способом, включаючи STDOUT, повернення функції тощо.

Приклади: 0, 1, 2, 3, 4, 5, 6, 7 повинні повернутися 1, 1, 1, 1, 2, 3, 6, 11.

Оцінка: Код гольфу, в байтах. Нехай найкоротший код виграє!

Стандартні лазівки заборонені.

Відповіді:


3

CJam (69 байт)

]qi:X,{1e|,:):N{N\f{1$%!*}W$.*:+}%1$W%.*:+N,/+}/W\+_1,*X=\_W%.*:+-Y/z

Демонстрація в Інтернеті

Пояснення

Основна ідея - реалізувати формуючу функцію, описану в OEIS. Вхід - це жахливий особливий випадок, але остаточні зміни, які я зробив, у результаті вийшли - 1 для цього випадку, тому z (для абсолютного значення) виправляє його. Ось найдивніший трюк тут.01z

.*:+повторюється три рази, і схоже, що він міг би зберегти байт, якщо вилучити як {.*:+}:F~. Однак це розривається зі спеціальним випадком , оскільки він зовсім не виконує зовнішню петлю.0


Ми використовуємо функцію допоміжної генерації для A000081 , умови якої мають повторення

a[0] = 0
a[1] = 1
For n >= 1, a[n+1] = (sum_{k=1}^n a[n-k+1] * sum_{d|k} d * a[d]) / n

Я впевнений, що деякі мови мають вбудовані зміни для зворотного перетворення Мебіуса , але CJam цього не робить; найкращий підхід, який я знайшов, - це створити відображення масиву d до, а потім зробити точне множення за допомогою . Зверніть увагу , що тут зручно збудували починаючи з індексу 1, тому що ми хочемо , щоб уникнути поділу на нуль при налаштуванні ваг. Зауважимо також, що якщо два масиви, що подаються на точкову операцію, не мають однакової довжини, то значення довшого з них залишаються недоторканими: тому ми повинні або брати перший k умовиdkd×a[d]dk % d == 0 ? d : 0a.*ak або змусити масив ваг підійти до n . Останнє здається коротшим. Отож, це обернене перетворення МебіусаanN\f{1$%!*}W$.*:+

Якщо ми називаємо результат зворотного перетворення Мебіуса M, ми тепер маємо

a[n+1]=1nk=1na[nk+1]×M[k]

aM1nn+1a

 qi:X,{   ,:):N{N\f{1$%!*}W$.*:+}%1$W%.*:+N,/+}/

Точка функції допоміжної генерації задається розділом формули A000055:

G.f.: A(x) = 1 + T(x) - T^2(x)/2 + T(x^2)/2,
where T(x) = x + x^2 + 2*x^3 + ... is the g.f. for A000081.

a

[x=0]+a[x]+12(a[x/2]i=0na[i]×a[ni])

a[x/2]x1,*X=

0\+a[0]=0X=0W\+2a[x]+i=0na[i]×a[ni]2a[x]

Отже, ми пояснили

 qi:X,{   ,:):N{N\f{1$%!*}W$.*:+}%1$W%.*:+N,/+}/W\+_1,*X=\_W%.*:+-Y/

1]N=1

1]qi:X,1>{ ... }/

X=0a[-1 1]0[x=0]X!+1e|

a1N=0

]qi:X,{ ... /+}/

очевидно дає поділ на нуль. Але якщо ми спробуємо

]qi:X,{1e| ... /+}/

тоді це працює. Ми отримуємо

             e# Stack: [] 0
1e|          e# Stack: [] 1
,:):N        e# Stack: [] [1]
{            e# We only execute this loop once
  N\f{1$%!*} e#   1 divides 1, so stack: [] [1]
  W$.*       e#   Remember: if the two arrays supplied to the pointwise operation
             e#   are not the same length then the values from the longer one are
             e#   left untouched. Stack: [] [1]
  :+         e#   Fold over a singleton. Stack: [] 1
}%           e# And that was a map, so stack: [] [1]
1$W%.*:+     e# Another [1] [] .*:+, giving the same result: 1
N,/          e# 1 / 1 = 1
+            e# And we append 1 to a giving [1]

що виробляє саме те значення, яке нам потрібно.

X=01[-1](112(1×1))=10111z


1

Pyth, 35 байт

l{m`SmSSMcXdUQk2.pQusm+L,dhHGhHtQ]Y

Демонстрація.

Цю програму можна розділити на дві частини: Спочатку ми генеруємо всі можливі дерева, потім видаляємо дублікати.

Цей код генерує дерева: usm+L,dhHGhHtQ]Y. Дерева представлені у вигляді об'єднаного списку країв, приблизно так:

[0, 1, 0, 2, 2, 3, 1, 4]

Кожне число означає вершину, а кожне два числа - край. Він побудований шляхом багаторазового додавання крайової стінки кожної можливої ​​вершини, яка вже існує, та нової, що була створена, і додаючи це до кожного можливого дерева з попереднього кроку. Це генерує всі можливі дерева, оскільки всі дерева можна генерувати шляхом багаторазового додавання однієї вершини та ребра від неї до існуючого дерева. Однак будуть створені ізоморфні дерева.

Далі для кожного дерева ми виконуємо всі можливі відновлення. Це робиться шляхом зіставлення всіх можливих перестановок вершин ( m ... .pQ), а потім перенесення дерева зі стандартного впорядкування до цього впорядкування XdUQk. dє дерево, kє перестановка.

Потім розділяємо краї в окремі списки c ... 2, сортуємо вершини в кожному краї SM, сортуємо краї в межах дерева S, даючи канонічне зображення кожного дерева. Ці два кроки - код mSSMcXdUQk2.pQ.

Тепер у нас є список списків, що складається з усіх можливих позначень кожного дерева. Ми сортуємо ці списки S. Будь-які два ізоморфних дерева повинні бути в змозі відновити до групи дерев. Використовуючи цей факт, ми перетворюємо кожен список у рядок із `, потім формуємо набір цих списків із {та виводимо його довжину l.

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