Partitionner la grille en triangles

18

Objectif

Le but de ce défi est de produire une fonction nqui calcule le nombre de façons de partitionner la n X 1grille en triangles où tous les sommets des triangles sont sur des points de grille.

Exemple

Par exemple, il existe 14 façons de partitionner la grille 2 x 1, donc f(2) = 14via les partitions suivantes Cloisons de 2 x 1 où les partitions ont respectivement 2, 2, 2, 2, 4 et 2 orientations distinctes.

Notation

C'est le , donc le code le plus court l'emporte.

Peter Kagey
la source
10
Certains cas de test supplémentaires seraient avantageux, afin que nous puissions vérifier que nos soumissions sont correctes.
AdmBorkBork
8
Vous souhaiterez peut-être spécifier des triangles non dégénérés .
Arnauld
1
J'ai apporté des modifications à la séquence OEIS A051708 pour refléter cette interprétation.
Peter Kagey

Réponses:

2

05AB1E , 13 octets

·LÉœÙεÅγo;P}O

Réponse de Port of @Bubbler 's Jelly .

Très lent en raison des permutations intégrées.

Essayez-le en ligne ou vérifiez les quatre premières entrées .

Explication:

·                # Double the (implicit) input
 L               # Create a list in the range [1, doubled_input]
  É              # Check for each if they're odd (1 if truthy, 0 is falsey)
                 # We now have a list of n 0s and n 1s (n being the input)
   œ             # Get all permutations of that list
    Ù            # Only leave the unique permutations
     ε     }     # Map each permutation to:
      Åγ         #  Run-length encode the current value (short for `γ€g`)
        o        #  Take 2 to the power for each
         ;       #  Halve each
          P      #  Take the product of the mapped permutation
            O    # Sum all mapped values together (and output implicitly)
Kevin Cruijssen
la source
19

Haskell , 60 55 54 52 octets

Après un dessin et une programmation de nombreux exemples, il m'est venu à l'esprit que c'est la même chose que le problème des tours:

Sur un échiquier (n+1)×(n+1) , combien y a-t-il de façons pour qu'une tour passe de (0,0) à (n,n) en se déplaçant simplement vers la droite +(1,0) ou vers le haut +(0,1) ?

Fondamentalement, vous avez le haut et le bas de la grille 1×n . Vous devez maintenant remplir la ligne non horizontale. Chaque triangle doit avoir deux lignes non horizontales. Que l'un de ses côtés fasse partie du haut ou de la ligne du bas correspond à la direction et à la longueur dans lesquelles vous iriez dans le problème des tours. Il s'agit d' OEIS A051708 . Pour illustrer cette correspondance, considérez les exemples suivants. Ici, la ligne supérieure correspond aux mouvements vers le haut, tandis que la ligne inférieure correspond aux mouvements vers la droite.

Merci @PeterTaylor pour -6 octets et @PostLeftGarfHunter pour -2 octets!

b 0=1
b 1=2
b n=div((10*n-6)*b(n-1)-9*(n-2)*b(n-2))n

Essayez-le en ligne!

flawr
la source
J'ai trouvé la séquence OEIS en cherchant avec les premières valeurs. Belle explication de la raison pour laquelle cela correspond. Voulez-vous le modifier pour ajouter un commentaire sur cette interprétation combinatoire alternative? Sinon, je pourrais.
Peter Taylor
BTW vous devez ajuster l'indexation, car la bonne réponse ici est A051708(n+1). J'ai donc posté la première bonne réponse :-P
Peter Taylor
Je suppose que la tour déplace la carte en triangles en faisant correspondre les triangles avec les bords supérieur et inférieur aux mouvements vers le haut ou vers la droite?
Neil
@PeterTaylor Damn, merci d'avoir signalé mon erreur :)
flawr
5
@Neil J'ai ajouté une explication graphique.
flawr
8

Haskell , 42 octets

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

Essayez-le en ligne!

Une implémentation assez directe qui se répète sur 2 variables.

Voici comment nous pouvons obtenir cette solution. Commencez avec le code implémentant une formule récursive directe:

54 octets

0%0=1
a%b=sum$map(a%)[0..b-1]++map(b%)[0..a-1]
f n=n%n

Essayez-le en ligne!

En utilisant l'interprétation de déplacement de tour de flawr , a%bc'est le nombre de chemins qui amènent la tour de (a,b)à (0,0), en utilisant uniquement les mouvements pour diminuer une coordonnée. Le premier mouvement diminue aou diminue b, en gardant l'autre le même, d'où la formule récursive.

49 octets

a?b=sum$map(a%)[0..b-1]
0%0=1
a%b=a?b+b?a
f n=n%n

Essayez-le en ligne!

Nous pouvons éviter la répétition en map(a%)[0..b-1]++map(b%)[0..a-1]notant que les deux moitiés sont identiques aet béchangées. L'appel auxiliaire a?bcompte les chemins où le premier mouvement diminue a, et b?acompte donc ceux où le premier mouvement diminue b. Ce sont en général différents, et ils s'ajoutent a%b.

La sommation en a?bpeut également être écrite comme une compréhension de liste a?b=sum[a%i|i<-[0..b-1]].

42 octets

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

Essayez-le en ligne!

Enfin, nous nous débarrassons %et écrivons simplement la récursivité en termes de ?en remplaçant a%ipar a?i+i?adans l'appel récursif.

Le nouveau cas de base fait que cela ?donne des sorties le double de celles de la ?version 49 octets, car avec 0?0=1, nous aurions 0%0=0?0+0?0=2. Cela permet d'utiliser définir f n=n?nsans réduire de moitié ce que nous aurions dû faire d'autre.

xnor
la source
Votre solution de 49 octets utilise la même récursivité que ma réponse, mais je n'ai pas encore trouvé celle de 42 octets. Une explication serait bien.
Peter Taylor
Je pense que j'ai utilisé la même approche dans l'un de mes programmes précédents: L'idée est de générer (ou de compter) toutes les partitions en générant les lignes non horizontales de droite à gauche. Vous commencez avec la ligne verticale. Ensuite, vous pouvez récursivement: prendre l'un des nœuds d'extrémité de la ligne précédente et le connecter à un nœud sur la ligne horizontale opposée qui est plus à gauche de tous les nœuds précédents sur cette ligne.
flawr
L'opérateur a%bcompte le nombre de partitions utilisant les nœuds 0,1,...,asur la ligne supérieure et les hochements 0,1,..,bde tête sur la ligne inférieure. L'opérateur a?bcompte le nombre de façons dont vous pouvez ajouter une nouvelle ligne à partir du nœud supérieur asi le nœud inférieur best déjà utilisé. (Vous pouvez vous connecter aà tous les noeuds [0,1,...,b-1], mais vous devez alors recurse pour chacun d'entre eux.)
flawr
@flawr, c'est celui de 49 octets, ce que je comprends. C'est celui ?de 42 octets que je ne connais pas, et ce qui est particulièrement curieux, c'est qu'il n'est pas symétrique.
Peter Taylor
@PeterTaylor Désolé pour la confusion, j'ai en quelque sorte mélangé les deux solutions. Je pense que nous pouvons assez facilement transformer les deux solutions l'une en l'autre: dans la première étape, nous pouvons remplacer map...par une compréhension de liste, dans la deuxième étape, nous ajoutons simplement la définition de %:a?b=sum$map(a%)[0..b-1], a%b=a?b+b?a a?b=sum[a%i|i<-[0..b-1]], a%b=a?b+b?a a?b=sum[a?i+i?a|i<-[0..b-1]]
flawr
7

CJam (24 octets)

{2,*e!{e`0f=:(1b2\#}%1b}

Démo en ligne

Cela utilise l'approche de Bubbler consistant à additionner les permutations de n0 et de n1.

Dissection

{         e# Define a block
  2,*     e#   Given input n, create an array of n 0s and n 1s
  e!      e#   Generate all permutations of that array
  {       e#   Map:
    e`    e#     Run-length encode
    0f=:( e#     Extract just the lengths and decrement them
    1b    e#     Sum
    2\#   e#     Raise 2 to the power of that sum
  }%
  1b      e#  Sum the mapped values
}

Approche alternative (28 octets)

{_1aa{_2$,f{j}@@,f{j}+1b}2j}

Démo en ligne

Dissection

Les triangles ont tous un bord horizontal et deux bords qui relient les lignes horizontales. Étiquetez les bords non horizontaux par un tuple de leurs deux x-coords et triez lexicographiquement. Ensuite, le premier bord est (0,0), le dernier bord est (n,n), et deux bords consécutifs diffèrent précisément dans l'une des deux positions. Cela en fait une récursivité simple, que j'ai implémentée en utilisant l'opérateur de récursion mémorisé j:

{            e# Define a block
  _          e#   Duplicate the argument to get n n
  1aa        e#   Base case for recursion: 0 0 => 1
  {          e#   Recursive body taking args a b
    _2$,f{j} e#     Recurse on 0 b up to a-1 b
    @@,f{j}  e#     Recurse on a 0 up to a b-1
    +1b      e#     Combine and sum
  }2j        e#   Memoised recursion with 2 args
}

Remarque

Ce n'est pas la première fois que je veux fjêtre soutenu dans CJam. Ici, cela ramènerait le score à 24 octets également. Je devrais peut-être essayer d'écrire un patch ...

Peter Taylor
la source
Oui, je vous ai battu de 10 secondes, je ne pense pas avoir été aussi proche :)
flawr
@flawr, j'ai envisagé de poster avant d'écrire une dissection, mais j'ai pensé que j'avais le temps de l'assommer rapidement. Puis j'ai vu "Nouvelle réponse", j'ai donc supprimé ma dissection partiellement écrite, publiée et éditée.
Peter Taylor
1
Merci pour -5 octets btw: D
flawr
4

Gelée , 15 14 octets

Ø.xŒ!QŒɠ€’§2*S

Essayez-le en ligne!

-1 octet basé sur le commentaire de Peter Taylor.

Utilise l'illustration de flawr directement, au lieu de la formule résultante.

Comment ça fonctionne

Ø.xŒ!QŒɠ€’§2*S    Main link (monad). Input: positive integer N.
Ø.x               Make an array containing N zeros and ones
   Œ!Q            All unique permutations
      Œɠ€         Run-length encode on each permutation
         ’§       Decrement and sum each
           2*S    Raise to power of 2 and sum

Prenez tous les itinéraires possibles sur une grille carrée. Le nombre de façons de déplacer les unités L dans une direction comme une tour est 2**(L-1). Appliquez ceci à chaque itinéraire et additionnez le nombre de façons de parcourir chaque itinéraire.

Bubbler
la source
Belle approche. Lorsque je l'ai porté sur CJam, il était plus court de diminuer les longueurs, la somme, puis de relever 2 jusqu'à la somme; plutôt que d'élever 2 à la longueur, de réduire de moitié, puis de multiplier. Je ne sais pas si cela pourrait vous faire économiser un octet.
Peter Taylor
3

Fusain , 44 31 octets

barré 44 est toujours régulier 44

F⊕θ«≔⟦⟧ηF⊕θ⊞ηΣ∨⁺ηEυ§λκ¹⊞υη»I⊟⊟υ

Essayez-le en ligne! Explication: Fonctionne en calculant le nombre de façons de partitionner un trapèze de longueurs de côtés opposés m,nen triangles qui reposent tous sur des décalages entiers. Il s'agit simplement d'un cas général du rectangle de taille ndans la question. Le nombre de partitions est donné récursivement comme la somme des nombres de partitions pour tous les côtés m,0..n-1et n,0..m-1. Cela équivaut au problème généralisé des tours , OEIS A035002 . Le code calcule simplement le nombre de partitions fonctionnant 0,0jusqu'à l' n,nutilisation des valeurs précédemment calculées au fur et à mesure.

F⊕θ«

Faites une boucle sur les rangées 0..n.

≔⟦⟧η

Commencez avec une ligne vide.

F⊕θ

Faites une boucle sur les colonnes de la ligne 0..n.

⊞ηΣ∨⁺ηEυ§λκ¹

Prenez la ligne jusqu'à présent et les valeurs des lignes précédentes dans la colonne actuelle, et ajoutez la somme totale à la ligne actuelle. Cependant, s'il n'y a aucune valeur, remplacez-la 1à la place de la somme.

⊞υη»

Ajoutez la ligne terminée à la liste des lignes jusqu'à présent.

I⊟⊟υ

Sortez la valeur finale calculée.

Neil
la source
2

Pari / GP , 43 octets

Selon OEIS , la fonction génératrice de cette séquence est

12(1-X1-9X+1)

n->Vec(sqrt((1-x)/(1-9*x)+O(x^n++))+1)[n]/2

Essayez-le en ligne!

alephalpha
la source