Suchen Sie für ein N x N- Bild einen Satz von Pixeln, sodass kein Abstand mehr als einmal vorhanden ist. Das heißt, wenn zwei Pixel durch einen Abstand d voneinander getrennt sind , sind dies die einzigen zwei Pixel, die durch genau d voneinander getrennt sind (unter Verwendung des euklidischen Abstands ). Beachten Sie, dass d keine Ganzzahl sein muss.
Die Herausforderung besteht darin, ein größeres Set als alle anderen zu finden.
Spezifikation
Es ist keine Eingabe erforderlich - für diesen Wettbewerb wird N auf 619 festgelegt.
(Da immer wieder gefragt wird, gibt es nichts Besonderes an der Nummer 619. Sie wurde so groß gewählt, dass eine optimale Lösung unwahrscheinlich ist, und so klein, dass ein N x N-Bild angezeigt werden kann, ohne dass Stack Exchange es automatisch verkleinert. Bilder können angezeigt in voller Größe bis zu 630 mal 630, und ich entschied mich für die größte Primzahl, die das nicht überschreitet.)
Die Ausgabe ist eine durch Leerzeichen getrennte Liste von Ganzzahlen.
Jede Ganzzahl in der Ausgabe stellt eines der Pixel dar, die in englischer Lesereihenfolge von 0 nummeriert sind. Beispiel: Bei N = 3 würden die Positionen in dieser Reihenfolge nummeriert sein:
0 1 2
3 4 5
6 7 8
Wenn Sie möchten, können Sie während des Laufens Fortschrittsinformationen ausgeben, solange die endgültige Ergebnisausgabe problemlos verfügbar ist. Sie können auf STDOUT oder in eine Datei ausgeben, oder was auch immer am einfachsten zum Einfügen in den Stapel-Snippet-Judge ist.
Beispiel
N = 3
Gewählte Koordinaten:
(0,0)
(1,0)
(2,1)
Ausgabe:
0 1 5
Gewinnen
Die Punktzahl ist die Anzahl der Positionen in der Ausgabe. Von den gültigen Antworten mit der höchsten Punktzahl gewinnt die Antwort, die am frühesten mit dieser Punktzahl ausgegeben wird.
Ihr Code muss nicht deterministisch sein. Sie können Ihre beste Ausgabe veröffentlichen.
Verwandte Forschungsbereiche
(Danke an Abulafia für die Golomb Links)
Keines von beiden ist mit diesem Problem identisch, aber beide haben ein ähnliches Konzept und geben Ihnen möglicherweise Anregungen, wie Sie dies angehen können:
- Golomb-Lineal : der eindimensionale Fall.
- Golomb-Rechteck : Eine zweidimensionale Erweiterung des Golomb-Lineals. Eine Variante des als Costas-Array bekannten NxN-Falls (Quadrat) wird für alle N gelöst.
Beachten Sie, dass die für diese Frage erforderlichen Punkte nicht denselben Anforderungen unterliegen wie ein Golomb-Rechteck. Ein Golomb-Rechteck erstreckt sich vom eindimensionalen Fall, indem der Vektor von jedem Punkt zum anderen eindeutig sein muss. Dies bedeutet, dass zwei Punkte horizontal um einen Abstand von 2 und zwei Punkte vertikal um einen Abstand von 2 voneinander getrennt sein können.
Für diese Frage muss der skalare Abstand eindeutig sein, daher kann es nicht gleichzeitig einen horizontalen und einen vertikalen Abstand von 2 geben. Jede Lösung für diese Frage ist ein Golomb-Rechteck, aber nicht jedes Golomb-Rechteck ist eine gültige Lösung für diese Frage.
Obergrenzen
Dennis wies im Chat hilfreich darauf hin, dass 487 eine Obergrenze für die Punktzahl ist und gab einen Beweis:
Gemäß meinem CJam-Code (
619,2m*{2f#:+}%_&,
) gibt es 118800 eindeutige Zahlen, die als Summe der Quadrate von zwei Ganzzahlen zwischen 0 und 618 (beide einschließlich) geschrieben werden können. n Pixel erfordern n (n-1) / 2 eindeutige Abstände voneinander. Für n = 488 ergibt dies 118828.
Es gibt also 118.800 mögliche unterschiedliche Längen zwischen allen möglichen Pixeln im Bild, und das Platzieren von 488 schwarzen Pixeln würde 118.828 Längen ergeben, was es unmöglich macht, dass sie alle eindeutig sind.
Es würde mich sehr interessieren zu hören, ob jemand einen Beweis für eine untere obere Schranke hat.
Bestenliste
(Beste Antwort von jedem Benutzer)
Stack Snippet Judge
quelle
Antworten:
Python 3,
135136137Wird mit einem gierigen Algorithmus gefunden, der in jeder Phase das gültige Pixel auswählt, dessen Abstandssatz zu den ausgewählten Pixeln sich mit dem der anderen Pixel am wenigsten überschneidet.
Insbesondere ist die Wertung
und das Pixel mit der niedrigsten Punktzahl wird ausgewählt.
Die Suche wird mit dem Punkt
10
(ie(0, 10)
) gestartet . Dieser Teil ist einstellbar, daher kann der Beginn mit unterschiedlichen Pixeln zu besseren oder schlechteren Ergebnissen führen.Es ist ein ziemlich langsamer Algorithmus, also versuche ich Optimierungen / Heuristiken und vielleicht ein bisschen Backtracking hinzuzufügen. PyPy wird für die Geschwindigkeit empfohlen.
Jeder, der versucht, einen Algorithmus zu entwickeln, sollte testen
N = 10
, für den ich 9 habe (dies erforderte jedoch viele Anpassungen und Versuche mit verschiedenen Anfangspunkten):Code
quelle
N=10
und es gibt viele verschiedene Layouts mit 9 Punkten, aber das ist das Beste, was Sie tun können.SWI-Prolog, Punktzahl 131
Kaum besser als die anfängliche Antwort, aber ich denke, dies wird die Dinge ein bisschen mehr in Gang bringen. Der Algorithmus ist derselbe wie die Python-Antwort, mit der Ausnahme, dass Pixel abwechselnd versucht werden, beginnend mit dem oberen linken Pixel (Pixel 0), dann dem unteren rechten Pixel (Pixel 383160), dann Pixel 1, dann Pixel 383159 , etc.
Eingang:
a(A).
Ausgabe:
Bild vom Stapel-Snippet
quelle
Haskell -
115130131135136Meine Inspiration war das Sieb von Eratosthenes und insbesondere das Echte Sieb von Eratosthenes , ein Artikel von Melissa E. O'Neill vom Harvey Mudd College. Meine ursprüngliche Version (die Punkte in der Indexreihenfolge berücksichtigte) hat Punkte extrem schnell gesiebt. Aus irgendeinem Grund kann ich mich nicht erinnern, dass ich mich entschlossen habe, die Punkte zu mischen, bevor ich sie in dieser Version "siebte" (ich denke nur, um die Generierung unterschiedlicher Antworten durch Verwendung zu vereinfachen) einen neuen Startwert im Zufallsgenerator). Da die Punkte nicht mehr in irgendeiner Reihenfolge vorliegen, wird nicht mehr wirklich gesiebt, sodass es nur ein paar Minuten dauert, bis diese einzelne 115-Punkte-Antwort vorliegt. Ein Knockout
Vector
wäre jetzt wahrscheinlich die bessere Wahl.Mit dieser Version als Kontrollpunkt sehe ich also zwei Zweige, die zum Algorithmus "Genuine Sieve" zurückkehren und die Listenmonade zur Auswahl nutzen oder die
Set
Operationen gegen Äquivalente austauschenVector
.Bearbeiten: zweiten Version habe ich mich wieder dem Siebalgorithmus zugewandt und die Erzeugung von „Multiples“ verbessert (Ausschalten von Indizes durch Finden von Punkten an ganzzahligen Koordinaten auf Kreisen mit einem Radius, der dem Abstand zwischen zwei beliebigen Punkten entspricht, ähnlich der Erzeugung von Primzahlen) ) und einige ständige Zeitverbesserungen vornehmen, indem unnötige Neuberechnungen vermieden werden.
Aus irgendeinem Grund kann ich mit aktivierter Profilerstellung keine Neukompilierung durchführen, aber ich glaube, dass der größte Engpass jetzt in der Rückverfolgung liegt. Ich denke, ein bisschen Parallelität und Parallelität zu erforschen, wird zu linearen Beschleunigungen führen, aber die Erschöpfung des Speichers wird mich wahrscheinlich zu einer zweifachen Verbesserung bringen.
Bearbeiten: Version 3 hat sich ein wenig gewandelt, und ich habe zuerst mit einer Heuristik experimentiert, indem ich die nächsten 𝐧 Indizes (nach dem Sieben aus früheren Auswahlen) genommen und denjenigen ausgewählt habe, der den nächsten minimalen Knockout-Satz erzeugt hat. Dies endete viel zu langsam, so dass ich zu einer Brute-Force-Methode mit ganzem Suchraum zurückkehrte. Die Idee, die Punkte nach Entfernung von einem Ursprung zu ordnen, kam mir und führte zu einer Verbesserung um einen einzelnen Punkt (in der Zeit, in der meine Geduld bestand). Bei dieser Version wird der Index 0 als Ursprung gewählt. Es kann sich lohnen, den Mittelpunkt der Ebene zu prüfen.
Bearbeiten: Ich habe 4 Punkte gesammelt, indem ich den Suchbereich neu geordnet habe, um die entferntesten Punkte von der Mitte zu priorisieren. Wenn Sie meinen Code testen, ist
135136 tatsächlich diezweitedritte gefundene Lösung. Schnelle Bearbeitung: Diese Version scheint am wahrscheinlichsten weiterhin produktiv zu sein, wenn sie weiter ausgeführt wird. Ich vermute, ich könnte mit 137 gleichziehen und dann keine Geduld mehr haben und auf 138 warten.Eine Sache habe ich bemerkt (die Hilfe für jemanden sein kann) , ist , dass , wenn Sie setzen den Punkt Reihenfolge von der Mitte der Ebene (dh Entfernen
(d*d -)
vonoriginDistance
) das Bild erzeugt sieht ein bisschen wie eine spärliche Primzahl Spirale.Ausgabe
quelle
d
die Anzahl der anderen von der Betrachtung ausgeschlossenen Punkte minimiert, indem Radiuskreised
mit Mittelpunkten der beiden ausgewählten Punkte nachgezeichnet werden, wobei der Umfang nur drei andere ganzzahlige Koordinaten berührt (bei 90, 180 und 270 Grad Drehung) der Kreis) und die senkrechte Halbierungslinie, die keine ganzzahligen Koordinaten schneidet. Somitn+1
schließt jeder neue Punkt6n
andere Punkte von der Betrachtung aus (bei optimaler Auswahl).Python 3, Punktzahl 129
Dies ist eine beispielhafte Antwort, um den Anfang zu machen.
Nur eine naive Herangehensweise, bei der die Pixel der Reihe nach durchlaufen werden und das erste Pixel ausgewählt wird, bei dem kein doppelter Abstand entsteht, bis die Pixel ausgehen.
Code
Ausgabe
Bild vom Stapel-Snippet
quelle
Python 3, 130
Zum Vergleich hier eine rekursive Backtracker-Implementierung:
Es findet die folgende 130-Pixel-Lösung schnell, bevor es zu ersticken beginnt:
Noch wichtiger ist, dass ich damit Lösungen für kleine Fälle überprüfe. Für
N <= 8
die optimalen sind:In Klammern sind die ersten lexikografischen Optimale aufgeführt.
Unbestätigt:
quelle
Scala, 132
Scannt von links nach rechts und von oben nach unten wie bei der naiven Lösung, versucht jedoch, an verschiedenen Pixelpositionen zu beginnen.
Ausgabe
quelle
Python, 134
132Hier ist eine einfache Methode, die einen Teil des Suchraums zufällig auswählt, um einen größeren Bereich abzudecken. Die Punkte in der Entfernung von einer Ursprungsreihenfolge werden iteriert. Dabei werden Punkte übersprungen, die sich in der gleichen Entfernung vom Ursprung befinden, und es wird frühzeitig abgebrochen, wenn keine Verbesserung der besten Ergebnisse erzielt werden kann. Es läuft auf unbestimmte Zeit.
Es findet schnell Lösungen mit 134 Punkten:
3097 3098 2477 4333 3101 5576 1247 9 8666 8058 12381 1257 6209 15488 6837 21674 19212 26000 24783 1281 29728 33436 6863 37767 26665 14297 4402 43363 50144 52624 18651 9996 588353 42792 6295 69950 48985 3435353353353 632 113313 88637 122569 11956 36098 79401 61471 135610 31796 4570 150418 57797 4581 125201 151128 115936 165898 127697 162290 33091 20098 189414 187620 186440 91290 206766 35619 69033 351 186511 129058 228458 69003567 23667 249115 21544 95185 231226 54354 104483 280665 518 147181 318363 1793 248609 82260 52568 365227 361603 346849 331462 69310 90988 341446 229599 277828 382837 339014 323612 365040 269883 307597 37446016 316
Für die Neugierigen sind hier einige brachiale kleine N:
quelle
Fantom 96
Ich habe einen Evolutionsalgorithmus verwendet, im Grunde genommen k zufällige Punkte auf einmal addiert, das für j verschiedene zufällige Mengen gemacht, dann die beste ausgewählt und wiederholt. Ziemlich schreckliche Antwort im Moment, aber das läuft mit nur 2 Kindern pro Generation aus Gründen der Geschwindigkeit, die fast nur zufällig ist. Ich werde ein bisschen mit den Parametern spielen, um zu sehen, wie es läuft, und ich brauche wahrscheinlich eine bessere Bewertungsfunktion als die Anzahl der verbleibenden freien Plätze.
Ausgabe
quelle
Python 3, 119
Ich kann mich nicht mehr erinnern, warum ich diese Funktion benannt habe
mc_usp
, obwohl ich vermute, dass sie etwas mit Markov-Ketten zu tun hat. Hier veröffentliche ich meinen Code, den ich ungefähr 7 Stunden mit PyPy laufen ließ. Das Programm versucht, 100 verschiedene Sätze von Pixeln aufzubauen, indem es zufällig Pixel auswählt, bis jedes Pixel im Bild überprüft wurde, und einen der besten Sätze zurückgibt.In einem anderen Punkt sollten wir wirklich versuchen, eine Obergrenze zu finden
N=619
, die besser als 488 ist, da diese Zahl nach den Antworten hier viel zu hoch ist. Rowan Blushs Kommentar, wie jeder neue Punktn+1
potenziell6*n
Punkte mit optimaler Auswahl entfernen kann, schien eine gute Idee zu sein. Leider ist diese Idee bei der Überprüfung der Formela(1) = 1; a(n+1) = a(n) + 6*n + 1
, bei dera(n)
die Anzahl der Punkte nach dem Hinzufügen vonn
Punkten zu unserer Menge entfernt wird, möglicherweise nicht die beste Lösung. Prüfen, wanna(n)
größer alsN**2
ista(200)
, größer als619**2
verspricht, abera(n)
größer als . Ich werde Sie auf dem Laufenden halten, wenn ich versuche, eine bessere Obergrenze zu finden, aber Vorschläge sind willkommen.10**2
ist, habena(7)
wir bewiesen, dass 9 die tatsächliche Obergrenze für istN=10
Auf meine Antwort. Erstens mein Satz von 119 Pixeln.
Zweitens mein Code, der zufällig einen Startpunkt aus einem Oktanten des 619x619-Quadrats auswählt (da der Startpunkt ansonsten bei Drehung und Reflexion gleich ist) und dann jeden zweiten Punkt aus dem Rest des Quadrats.
quelle