Compter les arbres

11

Un arbre est un graphe connecté, non orienté, sans cycles. Votre tâche consiste à compter le nombre d'arbres distincts avec un nombre donné de sommets.

Deux arbres sont considérés comme distincts s'ils ne sont pas isomorphes . Deux graphiques sont isomorphes si leurs sommets respectifs peuvent être appariés de telle sorte qu'il y ait une arête entre deux sommets dans un graphique si et seulement s'il y a une arête entre les sommets appariés à ces sommets dans l'autre graphique. Pour une description plus complète, voir le lien ci-dessus.

Pour voir à quoi ressemblent tous les arbres distincts des tailles 1 à 6, jetez un œil ici .

La série que vous essayez de sortir est A000055 à l'OEIS.

Restriction : votre solution doit prendre en minutes ou moins pour s'exécuter sur l'entrée 6. Ceci n'est pas destiné à éliminer les algorithmes de temps exponentiels, mais il est destiné à éliminer les algorithmes de temps doublement exponentiels, tels que le forçage brutal sur tous les ensembles de bords.

Entrée: tout entier non négatif.

L'entrée peut se faire par n'importe quel moyen standard, y compris STDIN, paramètre de ligne de commande, entrée de fonction, etc.

Sortie: Le nombre d'arbres distincts avec autant de sommets que l'entrée.

La sortie peut se faire par n'importe quel moyen standard, y compris STDOUT, retour de fonction, etc.

Exemples: 0, 1, 2, 3, 4, 5, 6, 7 devrait revenir 1, 1, 1, 1, 2, 3, 6, 11.

Notation: Code golf, par octets. Que le code le plus court gagne!

Failles standard interdites.

isaacg
la source

Réponses:

3

CJam (69 octets)

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

Démo en ligne

Explication

L'idée de base est de mettre en œuvre la fonction de génération décrite dans OEIS. L'entrée est un cas spécial désagréable, mais les derniers ajustements que j'ai faits ont fini par produire - 1 pour ce cas, donc le z0-1z (pour la valeur absolue) le range. C'est l'astuce la plus étrange ici.

.*:+est répété trois fois et semble pouvoir sauver un octet s'il est extrait en tant que {.*:+}:F~. Cependant, cela rompt avec le cas spécial , car il n'exécute pas du tout la boucle externe.0


Nous utilisons la fonction de génération auxiliaire pour A000081 , dont les termes ont la récurrence

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

Je suis sûr que certaines langues ont des fonctions intégrées pour la transformée de Möbius inverse , mais CJam ne le fait pas; la meilleure approche que j'ai trouvé est de construire une cartographie de tableau d à puis faire une multiplication ponctuelle avec unk×une[]k % d == 0 ? d : 0une utilisant .*. Notez qu'ici, il est pratique d'avoir construit départ à l'index 1, car nous voulons éviter la division par zéro lors de la configuration des poids. Notez également que si les deux tableaux fournis pour l'opération point par point ne sont pas de la même longueur, alors les valeurs de la plus longue restent inchangées: nous devons donc soit prendre le premier kak termes de ou faire monter le tableau de poids jusqu'à n . Ce dernier semble plus court. Donc, cette transformation de Möbius inverse représenteanN\f{1$%!*}W$.*:+

Si nous appelons le résultat de la transformée de Möbius inverse M, nous avons maintenant

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

aM1nn+1a

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

Le point de la fonction de génération auxiliaire est donné par la section de formule de 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\+une[0]=0X=0W\+-2une[X]+je=0nune[je]×une[n-je]2une[X]

Nous avons donc expliqué

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

1]N=1

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

X=0une[-1 1]0[X=0]X!+1e| .

une1N=0

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

donne évidemment la division par zéro. Mais si nous essayons

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

alors ça marche. On a

             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]

qui produit exactement la valeur dont nous avons besoin.

X=0-1[-1](-1-12(-1×-1))=-101-11z

Peter Taylor
la source
1

Pyth, 35 octets

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

Manifestation.

Ce programme peut être divisé en deux parties: d'abord, nous générons tous les arbres possibles, puis nous supprimons les doublons.

Ce code génère les arbres: usm+L,dhHGhHtQ]Y. Les arbres sont représentés comme une liste concaténée d'arêtes, quelque chose comme ceci:

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

Chaque nombre représente un sommet et tous les deux nombres sont une arête. Il est construit en ajoutant à plusieurs reprises une arête entre chaque sommet possible qui existe déjà et celui qui est nouvellement créé, et en l'ajoutant à chaque arbre possible de l'étape précédente. Cela génère tous les arbres possibles, car tous les arbres peuvent être générés en ajoutant à plusieurs reprises un sommet et une arête à l'arbre existant. Cependant, des arbres isomorphes seront créés.

Ensuite, pour chaque arbre, nous effectuons chaque réétiquetage possible. Cela se fait en mappant sur toutes les permutations possibles des sommets ( m ... .pQ), puis en faisant passer l'arbre de l'ordre standard à cet ordre, avec XdUQk. dest l'arbre, kest la permutation.

Ensuite, nous séparons les arêtes en listes distinctes avec c ... 2, trions les sommets à l'intérieur de chaque arête avec SM, trions les arêtes à l'intérieur de l'arbre avec S, donnant une représentation canonique de chaque arbre. Ces deux étapes sont le codemSSMcXdUQk2.pQ .

Maintenant, nous avons une liste de listes composées de chaque réétiquetage possible de chaque arbre. Nous trions ces listes avec S. Deux arbres isomorphes doivent pouvoir être réétiquetés dans le groupe d'arbres. En utilisant ce fait, nous convertissons chaque liste en une chaîne avec `, puis formons l'ensemble de ces listes avec {, et produisons sa longueur avec l.

isaacg
la source