Générer des séquences Skolem

10

Séquences de Skolem

Une séquence Skolem est une séquence de 2nnombres où chaque nombre ientre 1et nse produit exactement deux fois, et la distance entre les deux occurrences de iest exactement des iétapes. Voici quelques exemples de séquences Skolem:

1 1
1 1 4 2 3 2 4 3
16 13 15 12 14 4 7 3 11 4 3 9 10 7 13 12 16 15 14 11 9 8 10 2 6 2 5 1 1 8 6 5

Les séquences suivantes ne sont pas des séquences Skolem:

1 2 1 2      (The distance between the 1's is 2, not 1)
3 1 1 3      (The number 2 is missing)
1 1 2 1 1 2  (There are four 1's)

Objectif

Écrivez un programme, une fonction ou une expression pour compter le nombre de toutes les séquences Skolem d'une longueur donnée. Plus explicitement, votre entrée est un entier net votre sortie est le nombre de séquences Skolem de longueur 2n. Cette séquence a une entrée OEIS . Pour n = 0, vous pouvez retourner soit 0ou 1. Les premières valeurs, à partir de 0, sont

0, 1, 0, 0, 6, 10, 0, 0, 504, 2656, 0, 0, 455936, 3040560, 0, 0, 1400156768

Règles et notation

C'est le golf de code. Le format de sortie est laxiste dans des limites raisonnables.

boothby
la source
Juste curieux, mais quel est 0, 1, 0, 0, 6...votre question? Est-ce l'extrait de code, si oui, quelle langue est-ce?
PhiNotPi
2
Pourquoi le premier élément de votre sortie 0? Si vous allez l'admettre 0comme une entrée valide, la sortie devrait l'être 1.
Peter Taylor
1
Certains (y compris mon code) croient qu'il n'y a aucune séquence vide. Si 1 vous fait vous sentir mieux, retournez-le.
stand
2
AFAIK dans chaque contexte, vous supposez qu'il y a une et une seule séquence vide / objet nul / ensemble vide, etc. / fonction vers / depuis l'ensemble vide / graphique vide / quoi que ce soit d'autre.
Bakuriu
1
@boothby, tu viens d'appeler Knuth un imbécile?
Peter Taylor

Réponses:

8

GolfScript, 48 46 caractères

:b,1,{)2\?){{.2$&!{.2$|@@}*.+.4b?<}do;;}+%}@/,

La version plus rapide ( essayez en ligne ) - s'exécute assez rapidement, par exemple n=8prend environ deux secondes. Et l'approche choisie prend vraiment peu de caractères.

Cette version fonctionne également avec les bitmasks. Il construit le tableau de résultats possible à partir de 1, c'est-à-dire pour n=3:

1: 000011        000110 001100 011000 110000
2: 010111 101011 101110        011101 110101 111010

Alors que certains résultats (comme 000011) ont deux suites possibles, d'autres (par exemple 001100) n'en ont pas et sont supprimés du tableau de résultats.

Explication du code:

:b           # save the input into variable b for later use
,            # make the list 0..b-1 (the outer loop)
1,           # puts the list [0] on top of the stack - initially the only possible
             # combination
{)           # {...}@/ does the outer loop counting from i=1 to b
  2\?)       # computes the smalles possible bit mask m=2^i+1 with two bits set 
             # and distance of those equal to i (i.e. i=1: 11, i=2: 101, ...)
  {          # the next loop starts with this bitmask (prepended to code via
             # concatination {...}+
             # the loop itself iterates the top of the stack, i.e. at this point 
             # the result array                 
             # stack here contains item of result array (e.g. 00000011)
             # and bitmask (e.g. 00000101)
    {        # the inner-most loop tries all masks with the current item in the result set
      .2$&!  # do item and result set share not single bit? then - {...}*
      {
        .2$| # then generate the new entry by or-ing those two
        @@   # push it down on the stack (i.e. put working items to top)
      }*
      .+     # shift the bit mask left by one
      .4b?<  # if still in the range loop further
    }do;;    # removes the remainders of the loop (i.e. item processed and mask)
  }+%        # stack now contains the new result array
}@/
,            # length of result array, i.e. the number of Skolem sequences
Howard
la source
Accepter les solutions liées les plus rapides.
boothby
6

Expression J, 47 caractères

 +/*/"1((=&{:+.2-#@])#;.2)\"1~.(i.!+:y)A.,~>:i.y

Exemple:

    y=:5
    +/*/"1((=&{:+.2-#@])#;.2)\"1~.(i.!+:y)A.,~>:i.y
10

Prend environ 30 secondes pour y=:5sur ma machine.

l'algorithme est aussi lent que possible:

  • ~.(i.!+:y)A.,~>:i.ygénère chaque permutation 1 2 .. y 1 2 .. yet supprime les entrées en double
  • ((=&{:+.2-#@])#;.2)\"1 calcule:
    • (...)\"1 pour chaque préfixe de chaque ligne:
      • #;.2 compte les éléments avant chaque occurrence du dernier élément
      • #@] compte le nombre de comptes (c'est-à-dire le nombre d'occurrences du dernier élément)
      • =&{: détermine "l'égalité" "des" "derniers éléments" de la liste de comptage et de la liste d'origine.
      • +.est un OU logique. =&{:+.2-#@]lit "soit les derniers éléments [de la liste de comptage et la liste d'origine] sont égaux, soit il n'y a qu'un seul élément [dans la liste de comptage] plutôt que deux".
  • */"1 multiplie (ET logique) sur les lignes de la table de conditions, déterminant quelles permutations sont des séquences de Skolem.
  • +/ additionne les uns et les zéros ensemble.
John Dvorak
la source
6

GolfScript (46 caractères)

:&1,\,{0,2@)?)2&*{2${1$^}%@+\2*}*;+}/{4&?(=},,

Il s'agit d'une expression qui prend des entrées sur la pile. Pour le transformer en un programme complet qui prend des entrées sur stdin, ajoutez~

Il est assez inefficace - la plupart des économies que j'ai réalisées en jouant au golf à partir de 56 caractères non golfés l'ont été en élargissant la gamme de boucles de manière à ne pas introduire de résultats incorrects mais à calculer les déchets.

L'approche consiste à masquer au niveau du bit les produits cartésiens. Par exemple (en utilisant binaire pour les masques) pour n=4le code non golfé, le xor de chaque élément du produit cartésien serait calculé [00000011 00000110 ... 11000000] x [00000101 00001010 ... 10100000] x ... x [00010001 ... 10001000]. Tout résultat avec 8 bits ne pouvait être obtenu que par des masques sans chevauchement.

Afin d'optimiser la taille plutôt que la vitesse, le code accumule des produits partiels ( S1 u S1xS2 u S1xS2xS3 ...) et fait que chaque produit soit 2ncomposé d' éléments plutôt que simplement ceux 2n-1-iqui peuvent réellement contribuer à une séquence valide.

La vitesse

La version golfée dure n=510 secondes sur mon ordinateur et plus de 5 minutes n=6. La version originale non golfée calcule n=5en moins d'une seconde et n=6en environ 1 minute. Avec un simple filtre sur les résultats intermédiaires, il peut calculer n=8en 30 secondes. Je l'ai joué à 66 caractères (en tant que programme - 65 caractères comme expression) tout en gardant les boucles aussi restreintes que possible et en filtrant les collisions intermédiaires:

~:&1,\,{0,\).2\?)2&*@-{.{[\].~^.@~+<{;}*}+3$%@+\2*}*;\;}/{4&?(=},,
Peter Taylor
la source
Zut. Juste au moment où j'ai pensé que ma solution 48char J était assez bonne pour être publiée.
John Dvorak
Zut. Notre cravate à 47 caractères n'a pas duré très longtemps. +1
John Dvorak
5

GolfScript, 49 caractères

~:/..+?:d(,{d+/base(;:w;/,{.w?)w>1$?=},,/=},,/1=+

Attend le nombre nsur STDIN. C'est du code-golf - n'essayez pas le code avec nplus de 5.

Howard
la source
Aïe, pas plus de 5?
boothby
@boothby C'était la première tentative directe. Nous devons souvent prendre la vitesse de décision par rapport à la taille - et le code-golf concerne la taille. C'est pourquoi j'ai également ajouté la version rapide - qui était à l'origine beaucoup plus longue mais est maintenant encore plus courte.
Howard
0

Sauge, 70

C'est un peu plus court que mon original.

sum(1for i in DLXCPP([(i-1,j,i+j)for i in[1..n]for j in[n..3*n-i-1]]))

Comment ça fonctionne:

Étant donné une matrice 0/1, le problème de couverture exact pour cette matrice est de trouver un sous-ensemble des lignes qui résument (sous forme d'entiers) au vecteur tout-en-un. Par exemple,

11001
10100
01001
00011
00010

a une solution

10100
01001
00010

Mon approche préférée des problèmes consiste à les convertir en un problème de couverture exact. Les séquences de Skolem facilitent efficacement cela. Je fais un problème de couverture exacte où les solutions sont en bijection avec des séquences Skolem de longueur 2n. Par exemple, une ligne du problème pour n=6est

  a   |  b  
001000|001001000000 # S[b] = S[b+a+1] = a

où un 1 en position a < nsignifie que le symbole aest utilisé. Les positions restantes correspondent aux emplacements réels de la séquence. Une couverture exacte correspond à chaque symbole utilisé une seule fois et à chaque emplacement rempli une seule fois. Par construction, tout symbole kdans un emplacement est kéloigné de son partenaire.

Dans Sage, DLXCPPest une implémentation de "liens dansants" - elle résout le problème de couverture exacte d'une manière exceptionnellement gracieuse. C'est l'un de mes algorithmes préférés, et être à la surface dans Sage rend l'énumération combinatoire une joie.

boothby
la source
Wow, lien de danse. L'utilisation len(list(...))économisera 4 caractères.
Ray
@Ray Mon ordinateur mourrait simplement si je calculais len(list(...))pour n = 16. Et cela tuerait complètement le runtime.
stand
C'est vrai, car la conversion d'un générateur en liste coûte beaucoup de mémoire.
Ray