Füllen Sie die Zeilen, Spalten und Diagonalen eines NxN-Gitters mit 1 bis N

26

Aufgabe

Bei Eingabe von N wird ein NxN-Raster generiert und ausgegeben, wobei jede Zeile, Spalte und die beiden Diagonalen die Zahlen 1 bis N(oder 0 bis N-1, falls dies einfacher ist) enthalten.

Eingang

Die Eingabe ist eine positive Ganzzahl N. Es repräsentiert die Anzahl der Spalten und Zeilen im Raster. Bei diesem Problem können Sie davon ausgehen, dass Nes sich um eine angemessene Größe handelt, 4 ≤ N ≤ 8oder ( 1 ≤ N ≤ 8wenn Sie sich für den folgenden Bonus entscheiden).

Ausgabe

Die Ausgabe wird das N× N-Raster sein. In dem Raster enthält jede Zeile nur die Nummern 1 bis N, jede Spalte enthält nur die Nummern 1 bis Nund die beiden Längendiagonalen N(die von (0,0)bis (N-1,N-1)und die von (0,N-1)bis (N-1, 0)) enthalten nur die Nummern 1 bis N. Sie können die Zahlen 0 bis verwenden N−1. Für jede Ngibt es viele mögliche Lösungen, Sie müssen nur die erste drucken, die Sie finden. Sie müssen keine Leerzeichen zwischen den Zahlen drucken.

Einschränkungen

Ihr Code sollte wiederholt Ergebnisse für erzeugen können N >= 7. Das heißt, wenn Sie in der Lage sind, N = 7jedes Mal eine Lösung für Ihren Code zu finden, sind Sie gut. In Bezug auf eine absolute Grenze, sollte Ihr Code in der Lage sein , zu lösen N = 7in weniger als 10 Minuten jedes Mal , wenn Sie es laufen (dh , wenn Sie auf Zufallszahlen abhängen, für den schlimmsten Fall immer noch der Code unter 10 Minuten fertig in sollte N = 7) .

Beispiele

  • Eingang: 4

    Eine mögliche Ausgabe:

    1 2 3 4
    3 4 1 2
    4 3 2 1
    2 1 4 3
    
  • Eingang: 5

    Eine mögliche Ausgabe:

    1 2 3 4 5
    5 3 1 2 4
    2 5 4 3 1
    4 1 2 5 3
    3 4 5 1 2
    
  • Eingang: 8

    Eine mögliche Ausgabe:

    1 2 3 4 5 6 7 8
    2 3 1 5 4 8 6 7
    4 1 2 3 7 5 8 6
    6 4 7 8 1 2 3 5
    7 5 8 2 6 3 4 1
    5 8 4 6 2 7 1 3
    8 7 6 1 3 4 5 2
    3 6 5 7 8 1 2 4
    

Wertung

Dies ist , so dass mit einer Ausnahme der kürzeste Code in Bytes gewinnt. Für Eingaben N = 2, 3gibt es keine gültigen Lösungen. Wenn Ihr Code dies verarbeiten kann (vollständig ausgeführt, ohne in diesen Fällen etwas auszugeben oder eine leere Zeichenfolge auszugeben) und weiterhin N = 1(Ausgaben 1dafür) verarbeitet, sparen Sie 20% Ihrer Bytezahl.

hargasinski
quelle
1
Verwandte , aber ein solches Gitter wird hier aufgrund der Diagonalen Anforderung nicht funktionieren.
xnor
Ich mag diese Herausforderung, aber ich kann keinen Algorithmus für gerade Werte von herausfinden N. Dieser JavaScript-Code funktioniert N = 1, 5 or 7jedoch, wenn er jemandem hilft:for(o="",y=N;y--;o+="\n")for(x=N;x--;)o+=(((N-y)*2+x)%N)+1
user81655
Sehr verwandt, mögliches Duplikat: codegolf.stackexchange.com/q/47846/15599
Level River St
@steveverrill Das war aber kein Code-Golf.
Randomra
1
Vielleicht sollten Sie den N = 1Fall etwas genauer erläutern : Antworten, die auf den Bonus abzielen, sollten zurückgegeben werden 1, nicht die leere Zeichenfolge.
Lynn

Antworten:

3

Python 3, 275 260 Bytes * 0,8 = 220 208 Bytes

Rekursiver / Backtracking-Ansatz. Rist die rekursive Funktion, list die Spalte, wist die Zeile, Kist der nächste Eintrag.

Ich entschied mich dafür, es in ein 1d-Array zu setzen und es am Ende hübsch auszudrucken, um die Indizes einfacher zu machen.

r=range
n=(int)(input())
def R(A,I):
 l=I%n;w=I//n
 if I==n*n:[print(A[i*n:i*n+n])for i in r(n)];exit()
 for K in r(n):
  if all([all([A[i*n+l]!=K,w!=l or A[i+n*i]!=K,w!=n-1-l or A[n*i+n-i-1]!=K])for i in r(w)]+[A[w*n+i]!=K for i in r(l)]):R(A+[K],I+1)
R([],0)

Ungolfed-Version:

def Recurse(A,I,n):
 column=I%n
 row=I//n
 if I==n*n:
     [print(*A[i*n:i*n+n])for i in range(n)] # output
     exit() #end recursion
 for K in range(n):
    # try every possibility. Test if they satisfy the constraints:
    # if so, move the index on. If none of them do, we'll return None.
    # if a child returns None, we'll move onto the next potential child:
    # if all of them fail it will backtrack to the next level.
    if all([
        all([
            A[i*n+column]!=K, # column constraint
            row!=column or A[i+n*i]!=K, # diagonal constraint
            row!=n-1-column or A[n*i+n-i-1]!=K # antidiagonal constraint
            ]) for i in range(row)
        ]+[
            A[row*n+i]!=K for i in range(column) # row constraint
            ]):
        Recurse(A+[K],I+1,n)

Recurse([],0,(int)(input()))
Alexander-Brett
quelle
22

Funktion , nicht wettbewerbsfähig

AKTUALISIEREN! Massive Leistungssteigerung! n = 7 ist jetzt in weniger als 10 Minuten erledigt! Siehe Erklärung unten!

Es hat Spaß gemacht, darüber zu schreiben. Dies ist ein Brute-Force-Löser für dieses in Funciton geschriebene Problem. Einige Factoids:

  • Es akzeptiert eine Ganzzahl für STDIN. Beliebige Whitespaces unterbrechen den Text, einschließlich einer neuen Zeile nach der Ganzzahl.
  • Es verwendet die Zahlen 0 bis n - 1 (nicht 1 bis n ).
  • Es füllt das Raster „rückwärts“ aus, sodass Sie eine Lösung erhalten, bei der die untere Zeile 3 2 1 0und nicht die obere Zeile gelesen wird 0 1 2 3.
  • Es gibt richtig 0(die einzige Lösung) für n = 1 aus.
  • Leere Ausgabe für n = 2 und n = 3.
  • Wenn zu einer Exe kompiliert, dauert es ungefähr 8¼ Minuten für n = 7 (war ungefähr eine Stunde vor der Leistungsverbesserung). Ohne das Kompilieren (mit dem Interpreter) dauert es ungefähr 1,5-mal so lange, daher lohnt es sich, den Compiler zu verwenden.
  • Als persönlicher Meilenstein habe ich zum ersten Mal ein ganzes Funciton-Programm geschrieben, ohne es zuvor in einer Pseudocodesprache geschrieben zu haben. Ich habe es allerdings zuerst in C # geschrieben.
  • (Dies ist jedoch nicht das erste Mal, dass ich eine Änderung vorgenommen habe, um die Leistung von etwas in Funciton massiv zu verbessern. Das erste Mal war dies in der Fakultätsfunktion. Das Vertauschen der Reihenfolge der Operanden der Multiplikation hat einen großen Unterschied bewirkt.) Wie der Multiplikationsalgorithmus funktioniert (nur für den Fall, dass Sie neugierig sind.)

Ohne weiteres:

            ┌────────────────────────────────────┐           ┌─────────────────┐
            │                                  ┌─┴─╖ ╓───╖ ┌─┴─╖   ┌──────┐    │
            │                    ┌─────────────┤ · ╟─╢ Ӂ ╟─┤ · ╟───┤      │    │
            │                    │             ╘═╤═╝ ╙─┬─╜ ╘═╤═╝ ┌─┴─╖    │    │
            │                    │               └─────┴─────┘   │ ♯ ║    │    │
            │                  ┌─┴─╖                             ╘═╤═╝    │    │
            │     ┌────────────┤ · ╟───────────────────────────────┴───┐  │    │
          ┌─┴─╖ ┌─┴─╖   ┌────╖ ╘═╤═╝ ┌──────────┐         ┌────────┐ ┌─┴─╖│    │
          │ ♭ ║ │ × ╟───┤ >> ╟───┴───┘        ┌─┴─╖       │ ┌────╖ └─┤ · ╟┴┐   │
          ╘═╤═╝ ╘═╤═╝   ╘══╤═╝          ┌─────┤ · ╟───────┴─┤ << ╟─┐ ╘═╤═╝ │   │
    ┌───────┴─────┘ ┌────╖ │            │     ╘═╤═╝         ╘══╤═╝ │   │   │   │
    │     ┌─────────┤ >> ╟─┘            │       └───────┐      │   │   │   │   │
    │     │         ╘══╤═╝            ┌─┴─╖   ╔═══╗   ┌─┴─╖ ┌┐ │   │ ┌─┴─╖ │   │
    │     │           ┌┴┐     ┌───────┤ ♫ ║ ┌─╢ 0 ║ ┌─┤ · ╟─┤├─┤   ├─┤ Ӝ ║ │   │
    │     │   ╔═══╗   └┬┘     │       ╘═╤═╝ │ ╚═╤═╝ │ ╘═╤═╝ └┘ │   │ ╘═╤═╝ │   │
    │     │   ║ 1 ╟───┬┘    ┌─┴─╖       └───┘ ┌─┴─╖ │   │      │   │   │ ┌─┴─╖ │
    │     │   ╚═══╝ ┌─┴─╖   │ ɓ ╟─────────────┤ ? ╟─┘   │    ┌─┴─╖ │   ├─┤ · ╟─┴─┐
    │     ├─────────┤ · ╟─┐ ╘═╤═╝             ╘═╤═╝   ┌─┴────┤ + ╟─┘   │ ╘═╤═╝   │
  ┌─┴─╖ ┌─┴─╖       ╘═╤═╝ │ ╔═╧═╕ ╔═══╗ ┌───╖ ┌─┴─╖ ┌─┴─╖    ╘═══╝     │   │     │
┌─┤ · ╟─┤ · ╟───┐     └┐  └─╢   ├─╢ 0 ╟─┤ ⌑ ╟─┤ ? ╟─┤ · ╟──────────────┘   │     │
│ ╘═╤═╝ ╘═╤═╝   └───┐ ┌┴┐   ╚═╤═╛ ╚═╤═╝ ╘═══╝ ╘═╤═╝ ╘═╤═╝                  │     │
│   │   ┌─┴─╖ ┌───╖ │ └┬┘   ┌─┴─╖ ┌─┘           │     │                    │     │
│ ┌─┴───┤ · ╟─┤ Җ ╟─┘  └────┤ ? ╟─┴─┐   ┌─────────────┘                    │     │
│ │     ╘═╤═╝ ╘═╤═╝         ╘═╤═╝   │   │╔════╗╔════╗                      │     │
│ │       │  ┌──┴─╖ ┌┐   ┌┐ ┌─┴─╖ ┌─┴─╖ │║ 10 ║║ 32 ║    ┌─────────────────┘     │
│ │       │  │ << ╟─┤├─┬─┤├─┤ · ╟─┤ · ╟─┘╚══╤═╝╚╤═══╝ ┌──┴──┐                    │
│ │       │  ╘══╤═╝ └┘ │ └┘ ╘═╤═╝ ╘═╤═╝     │ ┌─┴─╖ ┌─┴─╖ ┌─┴─╖                  │
│ │     ┌─┴─╖ ┌─┴─╖  ┌─┴─╖  ┌─┴─╖ ╔═╧═╕     └─┤ ? ╟─┤ · ╟─┤ % ║                  │
│ └─────┤ · ╟─┤ · ╟──┤ Ӂ ╟──┤ ɱ ╟─╢   ├───┐   ╘═╤═╝ ╘═╤═╝ ╘═╤═╝                  │
│       ╘═╤═╝ ╘═╤═╝  ╘═╤═╝  ╘═══╝ ╚═╤═╛ ┌─┴─╖ ┌─┴─╖   │     └────────────────────┘
│         └─────┤      │            └───┤ ‼ ╟─┤ ‼ ║   │        ┌──────┐
│               │      │                ╘═══╝ ╘═╤═╝   │        │ ┌────┴────╖
│               │      │                      ┌─┴─╖   │        │ │ str→int ║
│               │      └──────────────────────┤ · ╟───┴─┐      │ ╘════╤════╝
│               │          ┌─────────╖        ╘═╤═╝     │    ╔═╧═╗ ┌──┴──┐
│               └──────────┤ int→str ╟──────────┘       │    ║   ║ │ ┌───┴───┐
│                          ╘═════════╝                  │    ╚═══╝ │ │ ┌───╖ │
└───────────────────────────────────────────────────────┘          │ └─┤ × ╟─┘
           ┌──────────────┐                                  ╔═══╗ │   ╘═╤═╝
╔════╗     │ ╓───╖ ┌───╖  │                              ┌───╢ 0 ║ │   ┌─┴─╖ ╔═══╗
║ −1 ║     └─╢ Ӝ ╟─┤ × ╟──┴──────┐                       │   ╚═╤═╝ └───┤ Ӂ ╟─╢ 0 ║
╚═╤══╝       ╙───╜ ╘═╤═╝         │                       │   ┌─┴─╖     ╘═╤═╝ ╚═══╝
┌─┴──╖ ┌┐ ┌───╖ ┌┐ ┌─┴──╖ ╔════╗ │                       │ ┌─┤   ╟───────┴───────┐
│ << ╟─┤├─┤ ÷ ╟─┤├─┤ << ║ ║ −1 ║ │                       │ │ └─┬─╜ ┌─┐ ┌─────┐   │
╘═╤══╝ └┘ ╘═╤═╝ └┘ ╘═╤══╝ ╚═╤══╝ │                       │ │   └───┴─┘ │   ┌─┴─╖ │
  │         └─┘      └──────┘    │                       │ └───────────┘ ┌─┤ ? ╟─┘
  └──────────────────────────────┘         ╓───╖         └───────────────┘ ╘═╤═╝
                               ┌───────────╢ Җ ╟────────────┐                │
      ┌────────────────────────┴───┐       ╙───╜            │
      │                          ┌─┴────────────────────┐ ┌─┴─╖
    ┌─┴─╖                      ┌─┴─╖                  ┌─┴─┤ · ╟──────────────────┐
    │ ♯ ║ ┌────────────────────┤ · ╟───────┐          │   ╘═╤═╝                  │
    ╘═╤═╝ │                    ╘═╤═╝       │          │     │              ┌───╖ │
┌─────┴───┘    ┌─────────────────┴─┐   ┌───┴───┐    ┌─┴─╖ ┌─┴─╖          ┌─┤ × ╟─┴─┐
│              │                 ┌─┴─╖ │   ┌───┴────┤ · ╟─┤ · ╟──────────┤ ╘═╤═╝   │
│              │ ┌───╖ ┌───╖  ┌──┤ · ╟─┘ ┌─┴─┐      ╘═╤═╝ ╘═╤═╝        ┌─┴─╖ │     │
│         ┌────┴─┤ ♭ ╟─┤ × ╟──┘  ╘═╤═╝   │ ┌─┴─╖ ┌───╖└┐ ┌──┴─╖      ┌─┤ · ╟─┘     │
│         │      ╘═══╝ ╘═╤═╝ ┌───╖ │     │ │ × ╟─┤ Ӝ ╟─┴─┤ ÷% ╟─┐    │ ╘═╤═╝ ┌───╖ │
│   ┌─────┴───┐     ┌────┴───┤ Ӝ ╟─┴─┐   │ ╘═╤═╝ ╘═╤═╝   ╘══╤═╝ │    │   └───┤ Ӝ ╟─┘
│ ┌─┴─╖ ┌───╖ │     │ ┌────╖ ╘═╤═╝   │   └───┘   ┌─┴─╖      │   │    └────┐  ╘═╤═╝
│ │ × ╟─┤ Ӝ ╟─┘     └─┤ << ╟───┘   ┌─┴─╖ ┌───────┤ · ╟───┐  │ ┌─┴─╖ ┌───╖ │    │
│ ╘═╤═╝ ╘═╤═╝         ╘══╤═╝   ┌───┤ + ║ │       ╘═╤═╝   ├──┴─┤ · ╟─┤ × ╟─┘    │
└───┤     └────┐ ╔═══╗ ┌─┴─╖ ┌─┴─╖ ╘═╤═╝ │ ╔═══╗ ┌─┴─╖ ┌─┴─╖  ╘═╤═╝ ╘═╤═╝      │
  ┌─┴─╖ ┌────╖ │ ║ 0 ╟─┤ ? ╟─┤ = ║  ┌┴┐  │ ║ 0 ╟─┤ ? ╟─┤ = ║    │     │ ┌────╖ │
  │ × ╟─┤ << ╟─┘ ╚═══╝ ╘═╤═╝ ╘═╤═╝  └┬┘  │ ╚═══╝ ╘═╤═╝ ╘═╤═╝    │     └─┤ << ╟─┘
  ╘═╤═╝ ╘═╤══╝ ┌┐     ┌┐ │     │     └───┘       ┌─┴─╖   ├──────┘       ╘═╤══╝
    │     └────┤├──┬──┤├─┘     ├─────────────────┤ · ╟───┘                │
    │          └┘┌─┴─╖└┘       │     ┌┐   ┌┐     ╘═╤═╝ ┌┐   ┌┐            │
    └────────────┤ · ╟─────────┘   ┌─┤├─┬─┤├─┐     └───┤├─┬─┤├────────────┘
                 ╘═╤═╝             │ └┘ │ └┘ │         └┘ │ └┘
                   └───────────────┘    │    └────────────┘

Erklärung der ersten Version

Die erste Version brauchte ungefähr eine Stunde, um n = 7 zu lösen . Im Folgenden wird hauptsächlich die Funktionsweise dieser langsamen Version erläutert. Unten erkläre ich, welche Änderung ich vorgenommen habe, um es auf unter 10 Minuten zu bringen.

Ein Ausflug in Bits

Dieses Programm benötigt Bits. Es braucht viele Teile, und es braucht sie an den richtigen Stellen. Erfahrene Funciton-Programmierer wissen bereits, dass Sie die Formel verwenden können , wenn Sie n Bits benötigen

2 ^ n-1

was in Funciton ausgedrückt werden kann als

(1 << n) - 1

Bei der Leistungsoptimierung ist mir aufgefallen, dass ich mit dieser Formel den gleichen Wert viel schneller berechnen kann:

¬ (−1 << n)

Ich hoffe, Sie verzeihen mir, dass ich nicht alle Gleichungsgrafiken in diesem Beitrag entsprechend aktualisiert habe.

Angenommen, Sie möchten keinen zusammenhängenden Bitblock. Tatsächlich möchten Sie in regelmäßigen Abständen n Bits für jedes k- te Bit, wie folgt:

                                 LSB
                                  ↓
00000010000001000000100000010000001
                            └──┬──┘
                               k

Die Formel dafür ist ziemlich einfach, sobald Sie es wissen:

((1 << k) - 1) / ((1 << k) - 1)

Im Code nimmt die Funktion Ӝdie Werte n und k und berechnet diese Formel.

Verfolgen Sie die verwendeten Nummern

Es gibt n ² Zahlen in dem letzten Raster, und jede Zahl kann eine beliebige sein , n mögliche Werte. Um davon zu halten Spurnummern in jeder Zelle erlaubt sind, halten wir eine Reihe , bestehend aus n ³ Bits, in dem ein Bit gesetzt wird , um anzuzeigen , dass ein bestimmte Wert genommen wird. Anfangs ist diese Zahl offensichtlich 0.

Der Algorithmus beginnt in der rechten unteren Ecke. Nachdem die erste Zahl eine 0 ist, müssen wir nachverfolgen, dass die 0 in keiner Zelle in derselben Zeile, Spalte und Diagonale mehr zulässig ist:

LSB                               (example n=5)
 ↓
 10000 00000 00000 00000 10000
 00000 10000 00000 00000 10000
 00000 00000 10000 00000 10000
 00000 00000 00000 10000 10000
 10000 10000 10000 10000 10000
                             ↑
                            MSB

Zu diesem Zweck berechnen wir die folgenden vier Werte:

  • Aktuelle Zeile: Wir müssen n Bits jedes n - te Bit (einer pro Zelle), und es dann auf die aktuelle Zeile verschieben r , jede Reihe enthält Erinnerung n ² Bits:

    ((1 << n²) −1) / ((1 << n) −1) << n²r

  • Aktuelle Spalte: Wir brauchen n Bits jedes n ²-te Bit (eine pro Zeile), und es dann zu der aktuellen Spalte verschieben c , jede Spalte enthält die Erinnerung n Bits:

    ((1 << n³) −1) / ((1 << n²) −1) << n²r

  • Vorwärtsdiagonale: Wir brauchen n Bits pro ... (Haben Sie aufgepasst? Schnell, finden Sie es heraus!) ... n ( n +1) Bit (gut gemacht!), Aber nur, wenn wir tatsächlich eingeschaltet sind die Vorwärtsdiagonale:

    ((1 << n² (n + 1)) - 1) / ((1 << n (n + 1)) - 1), wenn c = r

  • Rückwärtsdiagonale: Zwei Dinge hier. Erstens, woher wissen wir, ob wir uns in der Rückwärtsdiagonale befinden? Mathematisch ist die Bedingung c = ( n - 1) - r , was dasselbe ist wie c = n + (- r - 1). Hey, erinnert dich das an etwas? Das ist richtig, es ist das Zweierkomplement, also können wir die bitweise Negation (sehr effizient in Funciton) anstelle der Dekrementierung verwenden. Zweitens wird in der obigen Formel davon ausgegangen, dass das niedrigstwertige Bit gesetzt werden soll, in der Rückwärtsdiagonale jedoch nicht. Wir müssen es also um ... Wissen Sie, ... nach oben verschieben. Richtig, n ( n - 1).

    ((1 << n² (n-1)) - 1) / (1 << n (n-1)) - 1) << n (n-1), wenn c = n + r

    Dies ist auch die einzige, bei der wir möglicherweise durch 0 dividieren, wenn n = 1. Funciton ist dies jedoch egal. 0 ÷ 0 ist nur 0, weißt du nicht?

Im Code nimmt die Funktion Җ(die unterste) n und einen Index (aus dem r und c durch Division und Rest berechnet werden), berechnet diese vier Werte und ors sie zusammen.

Der Brute-Force-Algorithmus

Der Brute-Force-Algorithmus wird von Ӂ(der Funktion oben) implementiert . Es dauert n (die Rastergröße), Index (wo im Netz sind wir derzeit eine Reihe platzieren) und genommen (die Zahl mit n ³ Bits sagt uns , welche Zahlen wir können nach wie vor in jeder Zelle).

Diese Funktion gibt eine Folge von Zeichenfolgen zurück. Jede Zeichenfolge ist eine vollständige Lösung für das Raster. Es ist ein vollständiger Löser; es würde alle Lösungen zurückgeben, wenn Sie es zulassen, aber es gibt sie als eine verzögert bewertete Sequenz zurück.

  • Wenn der Index 0 erreicht hat, haben wir das gesamte Raster erfolgreich ausgefüllt, sodass wir eine Sequenz zurückgeben, die die leere Zeichenfolge enthält (eine einzelne Lösung, die keine der Zellen abdeckt). Die leere Zeichenfolge ist 0und wir verwenden die Bibliotheksfunktion , um daraus eine Einzelelementsequenz zu machen.

  • Die unten unter Leistungsverbesserung beschriebene Überprüfung findet hier statt.

  • Wenn der Index noch nicht 0 erreicht hat, dekrementieren wir ihn um 1, um den Index zu erhalten, bei dem wir jetzt eine Zahl platzieren müssen (nennen Sie das ix ).

    Wir erzeugen damit eine Lazy-Sequenz mit den Werten von 0 bis n - 1.

    Dann verwenden wir ɓ(monadic bind) mit einem Lambda, das die folgenden Schritte ausführt:

    • Schauen Sie sich zuerst das betreffende Bit an , um zu entscheiden, ob die Nummer hier gültig ist oder nicht. Wir können eine Zahl i genau dann setzen , wenn & (1 << ( n × ix ) << i ) nicht bereits gesetzt ist. Wenn es gesetzt ist, kehren Sie zurück 0(leere Sequenz).
    • Verwenden Sie Җdiese Option , um die Bits zu berechnen, die der aktuellen Zeile, Spalte und Diagonale (n) entsprechen. Verschieben sie durch i und dann ores auf genommen .
    • Rufen Sie rekursiv Ӂauf, um alle Lösungen für die verbleibenden Zellen abzurufen, und übergeben Sie die neue genommene und die dekrementierte ix . Dies gibt eine Folge unvollständiger Zeichenfolgen zurück. Jede Zeichenfolge enthält ix Zeichen (das Raster ist bis zum Index ix ausgefüllt ).
    • Verwenden Sie ɱ(map), um die auf diese Weise gefundenen Lösungen durchzugehen, und verwenden Sie, um i bis zum Ende jeder zu verketten . Fügen Sie eine neue Zeile hinzu, wenn der Index ein Vielfaches von n ist , andernfalls ein Leerzeichen.

Ergebnis generieren

Die wichtigsten Programmaufrufe Ӂ(die Brute Forcer) mit n , index = n ² (erinnern wir die Gitter nach hinten füllen) und genommen = 0 (zunächst nichts genommen wird). Wenn das Ergebnis eine leere Sequenz ist (keine Lösung gefunden), geben Sie den leeren String aus. Andernfalls geben Sie die erste Zeichenfolge in der Sequenz aus. Beachten Sie, dass dies bedeutet, dass nur das erste Element der Sequenz ausgewertet wird. Aus diesem Grund wird der Solver erst fortgesetzt, wenn alle Lösungen gefunden wurden.

Leistungsverbesserung

(Für diejenigen, die bereits die alte Version der Erklärung gelesen haben: Das Programm generiert keine Sequenz von Sequenzen mehr, die separat in einen String für die Ausgabe umgewandelt werden müssen. Es generiert nur noch eine Sequenz von Strings direkt. Ich habe die Erklärung entsprechend bearbeitet.) Aber das war nicht die Hauptverbesserung. Hier kommt es.)

Auf meinem Computer dauerte die kompilierte Exe der ersten Version ziemlich genau 1 Stunde, um n = 7 zu lösen . Dies war nicht innerhalb des vorgegebenen Zeitlimits von 10 Minuten, so dass ich mich nicht ausruhte. (Nun, eigentlich war der Grund, warum ich mich nicht ausgeruht habe, die Idee, wie ich es massiv beschleunigen kann.)

Der oben beschriebene Algorithmus stoppt seine Suche und geht jedes Mal zurück, wenn er auf eine Zelle stößt, in der alle Bits der aufgenommenen Zahl gesetzt sind, was anzeigt, dass nichts in diese Zelle eingegeben werden kann.

Der Algorithmus füllt jedoch weiterhin zwecklos das Gitter bis zu der Zelle, in der alle diese Bits gesetzt sind. Es wäre viel schneller, wenn es aufhören könnte, sobald in einer noch auszufüllenden Zelle bereits alle Bits gesetzt sind, was bereits darauf hinweist, dass wir den Rest des Gitters niemals lösen können, egal welche Zahlen wir eingeben es. Aber wie können Sie effizient prüfen, ob in einer Zelle n Bits gesetzt sind, ohne alle zu durchlaufen?

Der Trick beginnt mit dem Hinzufügen eines einzelnen Bits pro Zelle zur aufgenommenen Zahl. Anstelle dessen, was oben gezeigt wurde, sieht es jetzt so aus:

LSB                               (example n=5)
 ↓
 10000 0 00000 0 00000 0 00000 0 10000 0
 00000 0 10000 0 00000 0 00000 0 10000 0
 00000 0 00000 0 10000 0 00000 0 10000 0
 00000 0 00000 0 00000 0 10000 0 10000 0
 10000 0 10000 0 10000 0 10000 0 10000 0
                                       ↑
                                      MSB

Anstelle von n ³, gibt es nun n ² ( n + 1) Bits in dieser Nummer. Die Funktion, die die aktuelle Zeile / Spalte / Diagonale ausfüllt, wurde entsprechend geändert (tatsächlich, um ehrlich zu sein, komplett neu geschrieben). Diese Funktion füllt jedoch nur n Bits pro Zelle, so dass das soeben hinzugefügte zusätzliche Bit immer vorhanden ist 0.

Nehmen wir an, wir sind 1in der Mitte der Berechnung und haben gerade ein in die mittlere Zelle gestellt. Die aufgenommene Zahl sieht ungefähr so ​​aus:

                 current
LSB              column           (example n=5)
 ↓                 ↓
 11111 0 10010 0 01101 0 11100 0 11101 0
 00011 0 11110 0 01101 0 11101 0 11100 0
 11111 0 11110 0[11101 0]11100 0 11100 0    ← current row
 11111 0 11111 0 11111 0 11111 0 11111 0
 11111 0 11111 0 11111 0 11111 0 11111 0
                                       ↑
                                      MSB

Wie Sie sehen, sind die obere linke Zelle (Index 0) und die mittlere linke Zelle (Index 10) jetzt nicht mehr möglich. Wie bestimmen wir dies am effizientesten?

Betrachten Sie eine Zahl, bei der das 0. Bit jeder Zelle gesetzt ist, jedoch nur bis zum aktuellen Index. Eine solche Zahl lässt sich leicht mit der bekannten Formel berechnen:

((1 << (n + 1) i) - 1) / ((1 << (n + 1)) - 1)

Was würden wir bekommen, wenn wir diese beiden Zahlen addieren würden?

LSB                                               LSB
 ↓                                                 ↓
 11111 0 10010 0 01101 0 11100 0 11101 0           10000 0 10000 0 10000 0 10000 0 10000 0        ╓───╖
 00011 0 11110 0 01101 0 11101 0 11100 0     ║     10000 0 10000 0 10000 0 10000 0 10000 0            ║
 11111 0 11110 0 11101 0 11100 0 11100 0  ═══╬═══  10000 0 10000 0 00000 0 00000 0 00000 0  ═════   ╓─╜
 11111 0 11111 0 11111 0 11111 0 11111 0     ║     00000 0 00000 0 00000 0 00000 0 00000 0  ═════   ╨
 11111 0 11111 0 11111 0 11111 0 11111 0           00000 0 00000 0 00000 0 00000 0 00000 0          o
                                       ↑                                                 ↑
                                      MSB                                               MSB

Das Ergebnis ist:

             OMG
              ↓
        00000[1]01010 0 11101 0 00010 0 00011 0
        10011 0 00001 0 11101 0 00011 0 00010 0
═════   00000[1]00001 0 00011 0 11100 0 11100 0
═════   11111 0 11111 0 11111 0 11111 0 11111 0
        11111 0 11111 0 11111 0 11111 0 11111 0

Wie Sie sehen, fließt die Addition in das zusätzliche Bit, das wir hinzugefügt haben, über, aber nur, wenn alle Bits für diese Zelle gesetzt sind! Aus diesem Grund müssen Sie nur diese Bits ausblenden (gleiche Formel wie oben, aber << n ) und prüfen, ob das Ergebnis 0 ist:

00000[1]01010 0 11101 0 00010 0 00011 0    ╓╖    00000 1 00000 1 00000 1 00000 1 00000 1         ╓─╖ ╓───╖
10011 0 00001 0 11101 0 00011 0 00010 0   ╓╜╙╖   00000 1 00000 1 00000 1 00000 1 00000 1        ╓╜ ╙╖    ║
00000[1]00001 0 00011 0 11100 0 11100 0   ╙╥╥╜   00000 1 00000 1 00000 0 00000 0 00000 0  ═════ ║   ║  ╓─╜
11111 0 11111 0 11111 0 11111 0 11111 0   ╓╜╙╥╜  00000 0 00000 0 00000 0 00000 0 00000 0  ═════ ╙╖ ╓╜  ╨
11111 0 11111 0 11111 0 11111 0 11111 0   ╙──╨─  00000 0 00000 0 00000 0 00000 0 00000 0         ╙─╜   o

Wenn es nicht Null ist, ist das Gitter unmöglich und wir können aufhören.

  • Screenshot mit Lösung und Laufzeit für n = 4 bis 7.
Timwi
quelle
3
HEILIGER FICK. Alter, das ist beeindruckend.
Deusovi
1
Ich sage @ Deusovis Kommentar, danke, dass Sie sich so viel Mühe gegeben haben
hargasinski
7

Haskell, 790 * 0,80 = 632 Bytes

import Data.List
import Control.Monad
import Data.Array
s r=let{h as bs=[(a,b)|a<-as,b<-bs];(&)m k=(\(Just x)->x)$lookup k m;j=Just;n=Nothing;c=[1..r];q=delete;u=h[1..r]c;o=[(s,[u |u<-[h[1..r][c]|c<-c]++[h[r]c|r<-[1..r]]++[zip[1..r][1..r],zip[1..r][r,r-1..1]],s`elem`u])|s<-u];k=foldr(>=>)j;a p d g0=k[t p d2|d2<-q d(g0!p)]g0;t p d g0|not(d`elem`(g0!p))=j g0|[]<-v=n|[d2]<-v=k[t s2 d2|s2<-[(s,delete s$nub(concat(o&s)))|s<-u]&p]g1|True=k[l[s|s<-u,not(d`elem`v)]|u<-o&p]g1 where{v=q d(g0!p);g1=g0//[(p,v)];l[]_=n;l[d3]g=a d3 d g;l _ r=j r};w g0|and[case g0!s of{[_]->True;_->False}|s<-u]=j g0|True=msum[a s' d g0>>=w|d<-g0!s']where(_,s')=minimumBy(\(a,_)(b,_)->compare a b)[(l,s)|s<-u,let v=g0!s;l=length v,l>1]}in fmap(fmap(\[x]->x))$w$array((1,1),(r,r))[((i,j),[1..r])|i<-[1..r],j<-[1..r]]

Mir ist aufgefallen, dass dieses Problem dem Sudoku sehr ähnlich ist. Ich erinnere mich an einen alten Sudoku-Löser, den ich in Haskell basierend auf diesem anderen in Python geschrieben habe. Dies ist mein erster Code Golf Post oder Versuch.

Dies erfüllt den Bonus, weil es Nothingfür n=2,3und Just <result>für zurückgibt n>=4, wo <result>ein 2D-Array von Integralwerten ist.

Sehen hier für Online-Dolmetscher. Dieser Code ist tatsächlich länger als der in der Veröffentlichung angegebene, da der Online-Dolmetscher strengere Anforderungen an die Form eines vollständigen Programms stellt (Regeln besagen, dass eine Einreichung eine Funktion sein kann). Diese Einreichung wird als Funktionsargument eingegeben.

user2407038
quelle
1
Ein paar schnelle Tipps: a) Sie definieren c=[1..r], so dass Sie es in ound verwenden können w. b) minimumBy(\(a,_)(b,_)->compare a b)[...]ist head$sortOn fst[...]. c) die vin v=g0!swird nur einmal verwendet, so definieren sie nicht: l=length$g0!s. d) Sie haben noch einige Zwei-Buchstaben-Parameternamen. e) ersetzen Truemit 1<2und Falsemit 2<1. f) and[case g0!s of{[_]->True;_->False}|s<-u]ist all((==1).length.(g0!))u.
nimi
Kurztipps, Teil II: g) (&)m k=kann Infix definiert werden: m&k=. h) not(delem (g0!p))ist notElem d$g0!p. i) concat(...)ist id=<<(...). j) Verwenden Sie einen Infix-Operator für hz as%bs=.
nimi
3
Schnelle Metatipps: Sie können Code, der Backticks enthält, mit doppelten Backticks richtig einschränken ​``like`this``​!
Lynn
4

Pyth, 41 Bytes

#Km.SQQI.AmqQl{d+.TK.Tm,@@Kdd@@Kt-QddQB;K
#                                      ;   # while(True)
 Km.SQQ                                    # K = random QxQ 2d list
       I                               ;   # if ...
        .A                                 # all of...
          m                          Q     # map(range(Q))...
                +                          # concat
                 .TK                       # transpose K
                    .Tm,@@Kdd@@Kt-Qdd      # diagonals of K
                      m             d      # map(range(d))
                       ,                   # 2-elem list of...
                        @@Kdd              # K[n][n]
                             @@Kt-Qd       # and K[len(K)-n-1][n]
                    .T                     # transpose
           qQl{d                           # subarrays have no dups...
                                      B;   # ... then, break
                                        K  # output final result

Brute Force Ftw!

Da dies im Grunde genommen so lange versucht, zufälliges Mischen durchzuführen, bis es funktioniert (naja, es versucht es immer wieder n * [shuffle(range(n))]), dauert es sehr, sehr lange. Im Folgenden finden Sie einige Testläufe, die Ihnen einen Eindruck davon geben, wie lange es dauert:

llama@llama:~$ time echo 4 | pyth <(echo '#Km.SQQI.AmqQl{d+.TK.Tm,@@Kdd@@Kt-QddQB;K')               
[[2, 1, 0, 3], [0, 3, 2, 1], [3, 0, 1, 2], [1, 2, 3, 0]]
echo 4  0.00s user 0.00s system 0% cpu 0.001 total
pyth <(echo '#Km.SQQI.AmqQl{d+.TK.Tm,@@Kdd@@Kt-QddQB;K')  0.38s user 0.00s system 96% cpu 0.397 total

Das ist nur ein Geländewagen und dauert weniger als eine halbe Sekunde. Ich betrüge tatsächlich, weil dies das Beste aus ein paar Versuchen ist - die meisten von ihnen dauern über eine oder zwei Sekunden.

Ich habe noch kein Timing auf 5x5 bekommen (es lief einmal bis zum Abschluss, aber das war in einer REPL und ich habe es nicht timen).

Beachten Sie, dass die Regel für das Zeitlimit erst in der Frage bearbeitet wurde, nachdem diese Antwort veröffentlicht wurde.

Türknauf
quelle
Ich nehme an, dass dies nicht innerhalb von zehn Minuten 7x7 geht. ^^
Lynn
@ Mauris Naja, manchmal kann es ...;) Ist das eine Anforderung, die ich verpasst habe? Ich sehe nichts, was eine zeitliche Begrenzung in der Frage erwähnt.
Türklinke
Ich sehe es in den Kommentaren (nicht neuer Kommentar, vor 12 Stunden)
edc65
Tut mir leid, ich habe erst darüber
nachgedacht, als
1
+1 für die abstrakte ASCII-Grafik in Ihrer kommentierten Version. :)
Ilmari Karonen
3

SWI-Prolog, 326 × 0,80 = 260,8 Bytes

:-use_module(library(clpfd)).
a(N):-l(N,R),m(l(N),R),append(R,V),V ins 1..N,transpose(R,C),d(0,R,D),maplist(reverse,R,S),d(0,S,E),m(m(all_distinct),[R,C,[D,E]]),m(label,R),m(p,R).
l(L,M):-length(M,L).
d(X,[H|R],[A|Z]):-nth0(X,H,A),Y is X+1,(R=[],Z=R;d(Y,R,Z)).
p([H|T]):-write(H),T=[],nl;write(' '),p(T).
m(A,B):-maplist(A,B).

Bearbeiten: 16 Bytes dank @Mat gespeichert

Verwendung

Rufen Sie a(5).Ihren Dolmetscher an für N=5. Dies kehrt falsefür N=2oder zurückN=3 .

Da es die CLPFD-Bibliothek verwendet, ist dies keine reine Bruteforce. Dieses Programm kann N=20in ca. 15 Sekunden auf meinem Computer eine Lösung finden .

Ungolfed + Erklärungen:

Dies funktioniert im Grunde wie ein Sudoku-Löser, mit der Ausnahme, dass die Blockbedingungen durch die diagonalen Bedingungen ersetzt werden.

:-use_module(library(clpfd)).      % Import Constraints library

a(N):-
    l(N,R),                        % R is a list of length N
    maplist(l(N),R),               % R contains sublists, each of length N
    append(R,V),                   
    V ins 1..N,                    % Each value in the matrix is between 1 and N
    maplist(all_distinct,R),       % Values must be different on each row
    transpose(R,C),
    maplist(all_distinct,C),       % Values must be different on each column
    d(0,R,D),
    maplist(reverse,R,S),          
    d(0,S,E),
    all_distinct(D),               % Values must be different on the diagonal
    all_distinct(E),               % Values must be different on the "anti"-diagonal
    maplist(label,R),              % Affects actual values to each element
    maplist(p,R).                  % Prints each row

l(L,M):-length(M,L).               % True if L is the length of M

d(X,[H|R],[A|Z]):-nth0(X,H,A),Y is X+1,(R=[],Z=R;d(Y,R,Z)). % True if the third argument is the diagonal of the second argument

p([H|T]):-write(H),T=[],nl;write(' '),p(T).  % Prints a row separated by spaces and followed by a new line
Tödlich
quelle
Sehr schön! Sie können ein Byte speichern mit:maplist(maplist(all_distinct), [R,C,D,E])
mat
1
@mat Danke für den Vorschlag, spart 16 Bytes. Ich muss allerdings verwenden [R,C,[D,E]], weil Eund Deinfache Listen sind.
Fatalize
Richtig, sehr schöne Abhilfe!
Mat
2
@Fatalize Nur um Sie wissen zu lassen, Ihre Lösung war die beeindruckendste, da sie die einzige ist, die gelöst werden kannN=20
hargasinski
1
@Zequ Danke! Aber das liegt vor allem an der erstaunlichen CLPFD-Bibliothek von Prolog, die das Heben von Problemen wie diesen
übernimmt
2

CJam, 87 Bytes - 20% Bonus = 69,6 Bytes

qi__"@I/l
ŤˏūȻ
܀ᅀ൹৽჈͚
㑢鴑慚菥洠㬝᚜
"N/=:i0+\,m!f=`1LL](4e<=

Hardcodes die Antworten. Enthält einige nicht druckbare Elemente. Funktioniert N = 1durch N = 8.

Grundsätzlich enthält jede Zeile in dieser mysteriösen Zeichenfolge Indizes in der Liste der Permutationen von range(N), die als Unicode-Zeichen codiert sind.

=:i0+\,m!f=Indexiert die Liste der Permutationen und fügt am Ende der Liste der Indizes eine 0 hinzu, die die unterste Zeile darstellt 0 1 2 ... N-1. Denn N < 4das resultierende 2D-Array ist Unsinn.

`1LL]Erstellt eine Liste [N, pretty output, 1, "", ""]. Dann wird (4e<=das erste Element aus dieser Liste entfernt Nund das min(N, 4) % 4dritte Element aus dem Rest der Liste abgerufen . Denn N >= 4das ist die Ausgabe und ansonsten die Sonderausgabe für die ersten drei Fälle.

Probieren Sie es hier aus .

Lynn
quelle
0

C ++, 672 × 0,80 645 × 0,80 = 516 Bytes

#include <iostream>
int **b,**x,**y,*d,*a,n;
#define R(i) for(i=0;i<n;i++){
#define E(e) e=new int[n];
int f(int c,int r) {int i=0,p=c-1;if(r>=n)return 1;if(c == n + 1)return f(1,r+1);R(i)int m=r==i,s=r+i==n-1;if(!b[r][i]&&!x[r][p]&&!(m&&d[p])&&!(s&&a[p])&&!y[i][p]){b[r][i]=c;x[r][p]=1;y[i][p]=1;if(m)d[p]=1;if(s)a[p]=1;if(f(c+1,r))return 1;b[r][i]=0;x[r][p]=0;y[i][p]=0;if(m)d[p]=0;if(s)a[p]=0;}}return 0;}
int main(){std::cin>>n;int i=0,j=0;b=new int*[n];x=new int*[n];y=new int*[n];E(d);E(a);R(i)E(b[i]);E(x[i]);E(y[i]); d[i]=0;a[i]=0;R(j)b[i][j]=0;x[i][j]=0;y[i][j]=0;}}if(f(1,0)){R(i)R(j)std::cout<<b[i][j];}std::cout<<std::endl;}}}

Probieren Sie es hier online aus

Da bereits einige Antworten veröffentlicht wurden, dachte ich, ich würde die Golf-Version des Codes veröffentlichen, mit dem ich die Ausgabe für die Beispiele generiert habe. Ich beantworte zum ersten Mal einen , daher sind alle Rückmeldungen willkommen. :)

Ungolfed + Erklärungen:

Im Grunde ist der Code eine brachiale Lösung. Es beginnt in der ersten Reihe mit 0. Es beginnt an der ersten Stelle. Wenn diese Stelle alle Schecks besteht, geht es zur nächsten Stelle über. Wenn es die Zeile füllt, wird es in die nächste Zeile verschoben. Wenn alle Zeilen fertig sind, wurde eine Lösung gefunden. Wenn der Punkt nicht alle Schecks besteht, bewegt er sich zum nächsten Punkt. Wenn die Zeile fertig ist, wird zurückverfolgt, da eine Zahl in einer der vorherigen Zeilen verhindert, dass eine Lösung möglich ist.

#include <iostream>

// global variables to save bytes on passing these are function arguments
int **b, // this will store the state of the board
    **x, // if x[i][j] is true, row i of b contains the number j
    **y, // if y[i][j] is true, column i of b contains the number j
    *d,  // if d[i] the main diagonal of b contains i
    *a,  // if a[i] the antidiagonal of a contains i
    n;

// preprocessor to save bytes on repeated statements
#define R(i) for(i=0;i<n;i++){
#define E(e) e=new int[n];

// Recursively looks for a solution 
// c - the current number to insert in row r
// r - the current row to fill
int f (int c, int r) {
        int i=0,p=c-1;
        if (r >= n) return 1;             // we are done
        if (c == n + 1) return f(1,r+1);  // this row is full, move to the next row
        R(i)                              // go through the positions in this row,
                                                                            // trying to fill them with c
                int m=r==i, s=r+i==n-1;   // check if this position (r,i) is on ones
                                                                            // of the diagonals
                // if this spot isn't filled, and the row (r), column (i) and diagonals
                // (if it's on the diagonal) doesn't contain the number, fill the spot
                if (!b[r][i] && !x[r][p] && !(m&&d[p]) && !(s&&a[p]) && !y[i][p]) {
                        // fill the spot, and indicate that this row, column and diagonals 
                        // contain this number, c
                        b[r][i]=c; x[r][p]=1; y[i][p]=1;
                        if (m) d[p]=1; if (s)a[p]=1;

                        // move onto to the next number, if you find a solution, stop
                        if (f(c+1,r)) return 1;

                        // with this number in this spot, a solution is impossible, clear
                        // its, and clear the checks
                        b[r][i]=0; x[r][p]=0; y[i][p]=0;
                        if (m) d[p]=0; if (s) a[p]=0;
                }
        }

        return 0; // a solution wasn't found
}

int main() {
        std::cin >> n; // get n from STDIN

        // initialization 
        int i=0,j=0;
        b=new int*[n]; x=new int*[n]; y=new int*[n];
        E(d); E(a);
        R(i)
                E(b[i]); E(x[i]); E(y[i]); // initialization the inner arrays of b, x, y
                d[i]=0; a[i]=0;

                R(j)
                        b[i][j]=0; x[i][j]=0; y[i][j]=0; // ensure each point is initialized as 0
                }
        }

        // find a solution starting at the top-left corner and print it if it finds one
        if (f(1,0)) {
                R(i)
                        R(j)
                                std::cout<<b[i][j];
                        }
                        std::cout<<std::endl;
                }
        }
}
hargasinski
quelle
Nach dem erneuten Lesen des Codes stellte ich fest, dass einige der Überprüfungen möglicherweise nicht erforderlich sind, z if (x[r][p]) return f(c+1,r);. Ich arbeite daran, es zu verkürzen.
Hargasinski
0

Clojure, (215 + 258) · 0,8 = 378,4 (174 + 255) · 0,8 = 343,2

In zwei Teile teilen: Fehlerzählung S und eine anonyme Funktion, die die eigentliche Optimierung über die Tabu-Suche vornimmt .

Update: kürzer S (zählt eindeutige Werte innerhalb von Gruppen), weniger optimaler Startzustand (kein Shuffle).

(defn S[I n](count(mapcat set(vals(apply merge-with concat(flatten(for[R[(range n)]i R j R v[[(I(+(* n i)j))]]][{[1 i]v}{[2 j]v}(if(= i j){3 v})(if(=(- n 1 i)j){4 v})])))))))
#(if-let[s({1[0]2()3()}%)]s(loop[I(vec(for[R[(range %)]i R j R]i))P #{}](let[[s I](last(sort-by first(for[R[(range(count I))]i R j R I[(assoc(assoc I i(I j))j(I i))]:when(not(P I))][(S I %)I])))](if(=(*(+(* % 2)2)%)s)(partition % I)(recur I(conj P I))))))

Single-Core-Benchmarks (in Millisekunden) für 4, 5, 6 und 7 werden dreimal ausgeführt:

[[  131.855337   132.96267    138.745981]
 [ 1069.187325  1071.189488  1077.339372]
 [ 9114.736987  9206.65368   9322.656693]
 [36546.309408 36836.567267 36928.346312]]

Original:

(defn S[I n](apply +(flatten(for[p(concat(partition n I)(for[p(apply map vector(partition n(range(count I))))](map I p))[(take-nth(inc n)I)][(rest(butlast(take-nth(dec n)I)))])](remove #{1}(vals(frequencies p)))))))
#(if-let[s({1[0]2()3()}%)]s(loop[I(vec(flatten(map shuffle(repeat %(range %)))))P #{}](let[[s I](first(sort-by first(for[R[(range(count I))]i R j R I[(assoc(assoc I i(I j))j(I i))]:when(not(P I))][(S I %)I])))](if(= s 0)(partition % I)(recur I(conj P I))))))

Ich wünsche S es wäre kürzer, aber da es nur Vorkommen von mehr als einer / Partition zählt, ist das Stoppkriterium einfach (= s 0).

Viele CPU-Zyklen werden für nicht nützliche Auslagerungen verschwendet, zum Beispiel wird die Punktzahl nicht verbessert, wenn Sie auslagern 2 mit2 , und Sie müssen nicht zu Swap - Zahlen zwischen den Zeilen benötigen , da sie alle unterschiedliche Werte haben zu beginnen.

Benchmarks mit Intel 6700K (in Millisekunden):

(defn S[I n]( ... )
(def F #( ... ))

(defmacro mytime[expr]
  `(let [start# (. System (nanoTime)) ret# ~expr]
     (/ (double (- (. System (nanoTime)) start#)) 1000000.0)))

(pprint(vec(for[n[4 5 6 7]](vec(sort(repeatedly 5 #(mytime (F n)))))))

[[  43.445902   45.895107   47.277399   57.681634    62.594037]
 [ 222.964582  225.467034  240.532683  330.237721   593.686911]
 [2285.417473 2531.331068 3002.597908 6361.591714  8331.809410]
 [3569.62372  4779.062486 5725.905756 7444.941763 14120.796615]]

Multithreading mit pmap:

[[   8.881905  16.343714   18.87262  18.9717890   22.194430]
 [  90.963870 109.719332  163.00299  245.824443  385.365561]
 [ 355.872233 356.439256 1534.31059 2593.482767 3664.221550]
 [1307.727115 1554.00260 2068.35932 3626.878526 4029.543011]]
NikoNyrh
quelle