Generieren Sie Skolem-Sequenzen

10

Skolem-Sequenzen

Eine Skolem-Sequenz ist eine Folge von 2nZahlen, bei der jede Zahl izwischen 1und ngenau zweimal vorkommt und der Abstand zwischen den beiden Vorkommen von igenau iSchritte beträgt . Hier einige Beispiele für Skolem-Sequenzen:

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

Die folgenden Sequenzen sind keine Skolem-Sequenzen:

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)

Zielsetzung

Schreiben Sie ein Programm, eine Funktion oder einen Ausdruck, um die Anzahl aller Skolem-Sequenzen einer bestimmten Länge zu zählen. Genauer gesagt ist Ihre Eingabe eine Ganzzahl n, und Ihre Ausgabe ist die Anzahl der Skolem-Sequenzen mit einer Länge 2n. Diese Sequenz hat einen OEIS-Eintrag . Für n = 0kann kehren Sie entweder 0oder 1. Die ersten Werte, beginnend mit 0, sind

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

Regeln und Wertung

Das ist Code Golf. Das Ausgabeformat ist im Rahmen der Vernunft lax.

Standby
quelle
Nur neugierig, aber was ist das 0, 1, 0, 0, 6...in deiner Frage? Ist das das Code-Snippet, wenn ja, welche Sprache ist das?
PhiNotPi
2
Warum ist das erste Element in Ihrer Ausgabe 0? Wenn Sie 0als gültige Eingabe zugeben möchten, sollte die Ausgabe sein 1.
Peter Taylor
1
Einige (einschließlich meines Codes) glauben, dass es keine leeren Sequenzen gibt. Wenn Sie sich bei 1 besser fühlen, geben Sie es zurück.
Standby
2
AFAIK in jedem Kontext, von dem Sie annehmen, dass es eine und nur eine leere Sequenz / Nullobjekt / leere Menge usw. / Funktion-zu / von-der-leeren-Menge / leerer Graph / was auch immer gibt.
Bakuriu
1
@ Boothby, hast du Knuth gerade einen Narren genannt?
Peter Taylor

Antworten:

8

GolfScript, 48 46 Zeichen

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

Die schnellere Version ( online testen ) - läuft relativ schnell, z. B. n=8dauert etwa zwei Sekunden. Und der gewählte Ansatz braucht wirklich wenige Charaktere.

Diese Version funktioniert auch mit Bitmasken. Es baut das mögliche Ergebnisarray von 1 aufwärts auf, dh für n=3:

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

Während einige Ergebnisse (wie 000011) zwei mögliche Fortsetzungen haben, haben andere (dh 001100) keine und werden aus dem Ergebnisarray entfernt.

Erklärung des Codes:

: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
quelle
Akzeptieren der schnelleren gebundenen Lösungen.
Standby
6

J-Ausdruck, 47 Zeichen

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

Beispiel:

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

Dauert y=:5auf meinem Computer ungefähr 30 Sekunden .

Der Algorithmus ist so langsam wie möglich:

  • ~.(i.!+:y)A.,~>:i.ygeneriert jede Permutation von 1 2 .. y 1 2 .. yund entfernt doppelte Einträge
  • ((=&{:+.2-#@])#;.2)\"1 berechnet:
    • (...)\"1 für jedes Präfix jeder Zeile:
      • #;.2 zählt die Elemente vor jedem Auftreten des letzten Elements
      • #@] zählt die Anzahl der Zählungen (dh die Anzahl der Vorkommen des letzten Elements)
      • =&{: bestimmt die "Gleichheit" "der" letzten Elemente "der Zählliste und der ursprünglichen Liste.
      • +.ist ein logisches ODER. =&{:+.2-#@]liest "entweder die letzten Elemente [der Zählliste und der ursprünglichen Liste] sind gleich, oder es gibt nur ein Element [in der Zählliste] anstelle von zwei".
  • */"1 Multipliziert (logisches UND) über die Zeilen der Konditionstabelle und bestimmt, welche Permutationen Skolem-Sequenzen sind.
  • +/ summiert die Einsen und Nullen zusammen.
John Dvorak
quelle
6

GolfScript (46 Zeichen)

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

Dies ist ein Ausdruck, der Eingaben auf dem Stapel entgegennimmt. Um daraus ein vollständiges Programm zu machen, das Eingaben auf stdin übernimmt, stellen Sie vor~

Es ist ziemlich ineffizient - die meisten Einsparungen, die ich beim Golfen von 56 ungolfed Chars erzielt habe, waren die Erweiterung des Loop-Bereichs auf eine Weise, die keine falschen Ergebnisse liefert, sondern eine Abfallberechnung durchführt.

Der Ansatz ist die bitweise Maskierung kartesischer Produkte. ZB (unter Verwendung von Binär für die Masken) für n=4den ungolfed Code würde das xor jedes Elements im kartesischen Produkt berechnet [00000011 00000110 ... 11000000] x [00000101 00001010 ... 10100000] x ... x [00010001 ... 10001000]. Ein Ergebnis mit 8 Bit konnte nur durch nicht überlappende Masken erzielt werden.

Um die Größe und nicht die Geschwindigkeit zu optimieren, akkumuliert der Code Teilprodukte ( S1 u S1xS2 u S1xS2xS3 ...) und macht jedes Produkt aus 2nElementen und nicht nur aus Elementen, 2n-1-idie tatsächlich zu einer gültigen Sequenz beitragen können.

Geschwindigkeit

Die Golfversion läuft n=5in 10 Sekunden auf meinem Computer und mehr als 5 Minuten in n=6. Die ursprüngliche Version ohne Wolf berechnet n=5in weniger als einer Sekunde und n=6in etwa 1 Minute. Mit einem einfachen Filter für Zwischenergebnisse kann n=8in 30 Sekunden berechnet werden . Ich habe es auf 66 Zeichen (als Programm - 65 Zeichen als Ausdruck) gespielt, während ich die Schleifen so eingeschränkt wie möglich gehalten und Zwischenkollisionen gefiltert habe:

~:&1,\,{0,\).2\?)2&*@-{.{[\].~^.@~+<{;}*}+3$%@+\2*}*;\;}/{4&?(=},,
Peter Taylor
quelle
Verdammt. Gerade als ich dachte, meine 48char J-Lösung sei gut genug, um veröffentlicht zu werden.
John Dvorak
Verdammt. Unsere 47-Zeichen-Krawatte hielt nicht lange an. +1
John Dvorak
5

GolfScript, 49 Zeichen

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

Erwartet die Nummer nauf STDIN. Dies ist Code-Golf - versuchen Sie den Code nicht mit nmehr als 5.

Howard
quelle
Autsch, nicht größer als 5?
Standby
@ Boothby Es war der erste direkte Versuch. Wir müssen oft die Entscheidung zwischen Geschwindigkeit und Größe treffen - und beim Code-Golf geht es um Größe. Deshalb habe ich auch die schnelle Version hinzugefügt - die ursprünglich viel länger war, jetzt aber noch kürzer ist.
Howard
0

Salbei, 70

Dies ist etwas kürzer als mein Original.

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

Wie es funktioniert:

Bei einer gegebenen 0/1-Matrix besteht das genaue Deckungsproblem für diese Matrix darin, eine Teilmenge der Zeilen zu finden, die (als ganze Zahlen) zum All-One-Vektor summieren. Zum Beispiel,

11001
10100
01001
00011
00010

hat eine Lösung

10100
01001
00010

Meine bevorzugte Herangehensweise an Probleme besteht darin, sie auf ein genaues Deckungsproblem zu übertragen. Skolem-Sequenzen erleichtern dies effizient. Ich mache ein genaues Deckungsproblem, bei dem Lösungen mit Skolem-Längensequenzen in Konflikt geraten 2n. Für eine Zeile des Problems Zum Beispiel n=6ist

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

Dabei bedeutet eine 1 in Position a < n, dass das Symbol averwendet wird. Die verbleibenden Positionen entsprechen den tatsächlichen Positionen in der Sequenz. Eine genaue Abdeckung entspricht jedem Symbol, das genau einmal verwendet wird, und jeder Stelle, die genau einmal gefüllt wird. Jedes Symbol kan einem Ort ist konstruktionsbedingt kLeerzeichen von seinem Partner entfernt.

In Sage DLXCPPhandelt es sich um eine "Dance Links" -Implementierung, die das genaue Cover-Problem auf außergewöhnlich anmutige Weise löst. Es ist einer meiner Lieblingsalgorithmen überhaupt, und in Sage direkt an der Oberfläche zu sein, macht die kombinatorische Aufzählung zu einer Freude.

Standby
quelle
Wow, tanzende Verbindung. Bei Verwendung len(list(...))werden 4 Zeichen gespeichert.
Ray
@ Ray Mein Computer würde einfach sterben, wenn ich len(list(...))für n = 16 rechnen würde . Und es würde die Laufzeit völlig töten.
Standby
Das ist richtig, denn das Konvertieren eines Generators in eine Liste kostet viel Speicher.
Ray