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 N
es sich um eine angemessene Größe handelt, 4 ≤ N ≤ 8
oder ( 1 ≤ N ≤ 8
wenn 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 N
und 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 N
gibt 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 = 7
jedes 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 = 7
in 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 Codegolf , so dass mit einer Ausnahme der kürzeste Code in Bytes gewinnt. Für Eingaben N = 2, 3
gibt 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 1
dafür) verarbeitet, sparen Sie 20% Ihrer Bytezahl.
quelle
N
. Dieser JavaScript-Code funktioniertN = 1, 5 or 7
jedoch, wenn er jemandem hilft:for(o="",y=N;y--;o+="\n")for(x=N;x--;)o+=(((N-y)*2+x)%N)+1
N = 1
Fall etwas genauer erläutern : Antworten, die auf den Bonus abzielen, sollten zurückgegeben werden1
, nicht die leere Zeichenfolge.Antworten:
Python 3,
275260 Bytes * 0,8 =220208 BytesRekursiver / Backtracking-Ansatz.
R
ist die rekursive Funktion,l
ist die Spalte,w
ist die Zeile,K
ist 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.
Ungolfed-Version:
quelle
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:
3 2 1 0
und nicht die obere Zeile gelesen wird0 1 2 3
.0
(die einzige Lösung) für n = 1 aus.Ohne weiteres:
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
was in Funciton ausgedrückt werden kann als
Bei der Leistungsoptimierung ist mir aufgefallen, dass ich mit dieser Formel den gleichen Wert viel schneller berechnen kann:
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:
Die Formel dafür ist ziemlich einfach, sobald Sie es wissen:
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:
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:
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:
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:
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).
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 undor
s 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
0
und 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:0
(leere Sequenz).Җ
diese Option , um die Bits zu berechnen, die der aktuellen Zeile, Spalte und Diagonale (n) entsprechen. Verschieben sie durch i und dannor
es auf genommen .Ӂ
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 ).ɱ
(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:
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
1
in der Mitte der Berechnung und haben gerade ein in die mittlere Zelle gestellt. Die aufgenommene Zahl sieht ungefähr so aus: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:
Was würden wir bekommen, wenn wir diese beiden Zahlen addieren würden?
Das Ergebnis ist:
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:
Wenn es nicht Null ist, ist das Gitter unmöglich und wir können aufhören.
quelle
Haskell, 790 * 0,80 = 632 Bytes
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
Nothing
fürn=2,3
undJust <result>
für zurückgibtn>=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.
quelle
c=[1..r]
, so dass Sie es ino
und verwenden könnenw
. b)minimumBy(\(a,_)(b,_)->compare a b)[...]
isthead$sortOn fst[...]
. c) diev
inv=g0!s
wird nur einmal verwendet, so definieren sie nicht:l=length$g0!s
. d) Sie haben noch einige Zwei-Buchstaben-Parameternamen. e) ersetzenTrue
mit1<2
undFalse
mit2<1
. f)and[case g0!s of{[_]->True;_->False}|s<-u]
istall((==1).length.(g0!))u
.(&)m k=
kann Infix definiert werden:m&k=
. h)not(d
elem(g0!p))
istnotElem d$g0!p
. i)concat(...)
istid=<<(...)
. j) Verwenden Sie einen Infix-Operator fürh
zas%bs=
.``like`this``
!Pyth, 41 Bytes
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: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.
quelle
SWI-Prolog, 326 × 0,80 = 260,8 Bytes
Bearbeiten: 16 Bytes dank @Mat gespeichert
Verwendung
Rufen Sie
a(5).
Ihren Dolmetscher an fürN=5
. Dies kehrtfalse
fürN=2
oder zurückN=3
.Da es die CLPFD-Bibliothek verwendet, ist dies keine reine Bruteforce. Dieses Programm kann
N=20
in 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.
quelle
maplist(maplist(all_distinct), [R,C,D,E])
[R,C,[D,E]]
, weilE
undD
einfache Listen sind.N=20
CJam, 87 Bytes - 20% Bonus = 69,6 Bytes
Hardcodes die Antworten. Enthält einige nicht druckbare Elemente. Funktioniert
N = 1
durchN = 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 darstellt0 1 2 ... N-1
. DennN < 4
das resultierende 2D-Array ist Unsinn.`1LL]
Erstellt eine Liste[N, pretty output, 1, "", ""]
. Dann wird(4e<=
das erste Element aus dieser Liste entferntN
und dasmin(N, 4) % 4
dritte Element aus dem Rest der Liste abgerufen . DennN >= 4
das ist die Ausgabe und ansonsten die Sonderausgabe für die ersten drei Fälle.Probieren Sie es hier aus .
quelle
C ++,
672 × 0,80645 × 0,80 = 516 BytesProbieren 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 Code-Golf , 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.
quelle
if (x[r][p]) return f(c+1,r);
. Ich arbeite daran, es zu verkürzen.Clojure,
(215 + 258) · 0,8 = 378,4(174 + 255)· 0,8 = 343,2In 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).Single-Core-Benchmarks (in Millisekunden) für 4, 5, 6 und 7 werden dreimal ausgeführt:
Original:
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):
Multithreading mit
pmap
:quelle