n
Berechnen Sie bei gegebener Ganzzahl eine Menge n
zufälliger eindeutiger Ganzzahlen im Bereich 1..n^2
(einschließlich) so, dass die Summe der Menge gleich istn^2
Zufällig bedeutet in diesem Fall gleichmäßig zufällig zwischen gültigen Ausgaben. Jede gültige Ausgabe für eine bestimmte Ausgabe n
muss eine einheitliche Chance haben, generiert zu werden.
Zum Beispiel n=3
sollte eine 1/3 Chance jeweils Ausgeben hat 6, 1, 2
, 3, 5, 1
oder 4, 3, 2
. Da es sich um eine Menge handelt, ist die Reihenfolge irrelevant und 4, 3, 2
identisch mit3, 2, 4
Wertung
Der Gewinner ist das Programm, das in weniger als n
60 Sekunden den höchsten Wert berechnen kann .
Hinweis: Um eine mögliche teilweise Hardcodierung zu verhindern, müssen alle Einträge unter 4000 Byte liegen
Testen
Der gesamte Code wird auf meinem lokalen Windows 10-Computer ausgeführt (Razer Blade 15, 16 GB RAM, Intel i7-8750H 6-Kerne, 4,1 GHz, GTX 1060, falls Sie die GPU missbrauchen möchten). Geben Sie daher bitte detaillierte Anweisungen zum Ausführen Ihres Codes an meine Maschine.
Auf Anfrage können Einträge entweder über Debian in der WSL oder auf einer virtuellen Xubuntu-Maschine ausgeführt werden (beide auf derselben Maschine wie oben).
Die Einreichungen werden 50 Mal hintereinander durchgeführt. Das Endergebnis ist ein Durchschnitt aller 50 Ergebnisse.
quelle
Antworten:
Rust , n ≈ 1400
Wie man läuft
Bauen mit
cargo build --release
und laufen mittarget/release/arbitrary-randomness n
.Dieses Programm läuft am schnellsten mit viel Speicher (solange es natürlich nicht ausgetauscht wird). Sie können die Speichernutzung anpassen, indem Sie die
MAX_BYTES
Konstante bearbeiten , die derzeit auf 8 GiB eingestellt ist.Wie es funktioniert
Die Menge wird durch eine Folge von binären Entscheidungen konstruiert (jede Zahl befindet sich entweder innerhalb oder außerhalb der Menge), deren Wahrscheinlichkeiten kombinatorisch berechnet werden, indem die Anzahl möglicher Mengen gezählt wird, die nach jeder Auswahl unter Verwendung dynamischer Programmierung konstruierbar sind.
Die Speichernutzung für große n wird durch die Verwendung einer Version dieser Binomialpartitionierungsstrategie reduziert .
Cargo.toml
src/main.rs
Probieren Sie es online aus!
(Hinweis: Die TIO-Version enthält einige Änderungen. Erstens ist das Speicherlimit auf 1 GiB reduziert. Zweitens habe ich, da Sie mit TIO keine schreiben können
Cargo.toml
und von externen Kisten abhängig sindrand
, stattdessen mit derdrand48
aus der C-Bibliothek gezogen FFI. Ich habe mich nicht darum gekümmert, es zu setzen, daher wird die TIO-Version bei jedem Lauf das gleiche Ergebnis erzielen. Verwenden Sie die TIO-Version nicht für offizielles Benchmarking.)quelle
ln_add_exp
indem Sie prüfen, ob die absolute Differenz größer als ~ 15 ist. Dies kann schneller sein, wenn viele solcher Additionen vorhanden sind.ln_add_exp
Anrufe beinhalten vergleichbare Eingaben.Java 7+, n = 50 in ~ 30 Sekunden auf TIO
Ungolfed-Version meiner Antwort für die Code-Golf-Version dieser Herausforderung mit nur einer geringfügigen Änderung: Wird
java.util.Random#nextInt(limit)
anstelle(int)(Math.random()*limit)
einer Ganzzahl im Bereich verwendet[0, n)
, da sie ungefähr doppelt so schnell ist .Probieren Sie es online aus.
Erläuterung:
Verwendeter Ansatz:
Der Code ist in zwei Teile unterteilt:
n
zufälligen Ganzzahlen, die sich summierenn squared
.Schritt 1 wird mit den folgenden Unterschritten ausgeführt:
1) Generieren Sie ein Array
n-1
mit zufälligen Ganzzahlen im Bereich[0, n squared)
. Und füge0
undn squared
zu dieser Liste hinzu. Dies geschieht in derO(n+1)
Leistung.2) Dann wird das Array mit dem eingebauten Array sortiert
java.util.Arrays.sort(int[])
. Dies erfolgt in derO(n*log(n))
Leistung, wie in den Dokumenten angegeben:3) Berechnen Sie die Differenz zwischen jedem Paar. Diese resultierende Liste von Unterschieden enthält
n
Ganzzahlen, die sich zu summierenn squared
. Dies geschieht in derO(n)
Leistung.Hier ein Beispiel:
Diese drei obigen Schritte sind also ziemlich gut für die Leistung, im Gegensatz zu Schritt 2 und der Schleife um das Ganze, die eine grundlegende Brute-Force ist. Schritt 2 ist in folgende Unterschritte unterteilt:
1) Die Differenzliste ist bereits in a gespeichert
java.util.Set
. Es wird geprüft, ob die Größe dieses Sets gleich istn
. Wenn dies der Fall ist, bedeutet dies, dass alle von uns generierten Zufallswerte eindeutig sind.2) Und es wird auch prüfen, ob es nicht enthält
0
im Set, da die Herausforderung für Zufallswerte im Bereich fragt[1, X]
, woX
istn squared
abzüglich der Summe der[1, ..., n-1]
, wie angegeben @Skidsdev unten im Kommentar.Wenn eine der beiden oben genannten Optionen (nicht alle Werte sind eindeutig oder eine Null vorhanden) vorhanden ist, wird ein neues Array generiert und durch Zurücksetzen auf Schritt 1 erneut festgelegt. Dies wird fortgesetzt, bis ein Ergebnis vorliegt. Aus diesem Grund kann die Zeit sehr unterschiedlich sein. Ich habe gesehen, dass es in 3 Sekunden einmal auf TIO beendet wurde
n=50
, aber auch einmal in 55 Sekundenn=50
.Beweis der Einheitlichkeit:
Ich bin mir nicht ganz sicher, wie ich das beweisen soll, um ganz ehrlich zu sein. Das
java.util.Random#nextInt
ist sicher einheitlich, wie in den Dokumenten beschrieben:Die Unterschiede zwischen diesen (sortierten) Zufallswerten selbst sind natürlich nicht einheitlich, aber die Mengen als Ganzes sind einheitlich. Auch hier bin ich mir nicht sicher, wie ich das mathematisch beweisen soll, aber hier ist ein Skript, das
10,000
generierte Mengen (fürn=10
) in eine Karte mit einem Zähler einfügt , wobei die meisten Mengen eindeutig sind. einige wiederholten sich zweimal; und das maximale wiederholte Auftreten liegt gewöhnlich im Bereich[4,8]
.Installationsanleitung:
Da Java eine ziemlich bekannte Sprache mit vielen verfügbaren Informationen zum Erstellen und Ausführen von Java-Code ist, werde ich mich kurz fassen.
Alle in meinem Code verwendeten Tools sind in Java 7 verfügbar (vielleicht sogar bereits in Java 5 oder 6, aber verwenden wir 7 nur für den Fall). Ich bin mir ziemlich sicher, dass Java 7 bereits archiviert ist, daher würde ich empfehlen, Java 8 herunterzuladen, um meinen Code auszuführen.
Gedanken zu Verbesserungen:
Ich möchte eine Verbesserung für die Prüfung auf Nullen finden und prüfen, ob alle Werte eindeutig sind. Ich könnte
0
vorherArrayList
nachsehen , indem ich sicherstelle, dass der Zufallswert, den wir dem Array hinzufügen, nicht bereits darin enthalten ist, aber es würde ein paar Dinge bedeuten: Das Array sollte ein sein, damit wir die eingebaute Methode verwenden können.contains
; Eine while-Schleife sollte hinzugefügt werden, bis wir einen zufälligen Wert gefunden haben, der noch nicht in der Liste enthalten ist. Da die Überprüfung auf Null jetzt mit.contains(0)
dem Set durchgeführt wird (das nur einmal überprüft wird), ist es für die Leistung höchstwahrscheinlich besser, sie an diesem Punkt zu überprüfen, als die Schleife mit.contains
in der Liste hinzuzufügen , die mindestens einmal überprüftn
wird , aber höchstwahrscheinlich mehr.Bei der Eindeutigkeitsprüfung haben wir nur die
n
Anzahl der zufälligen Ganzzahlen, die sichn squared
nach Schritt 1 des Programms summieren. Erst dann können wir prüfen, ob alle eindeutig sind oder nicht. Es könnte möglich sein, eine sortierbare Liste anstelle eines Arrays zu führen und die Unterschiede dazwischen zu überprüfen, aber ich bezweifle ernsthaft, dass dies die Leistung verbessern wird, als sie nur in eine Liste zu setzenSet
und zu überprüfen, ob die Größe dieses Setsn
einmal ist.quelle
n^2 - sum(1..n-1)
zum Beispiel fürn=5
die größte gültige Zahl5^2 - sum(1, 2, 3, 4) == 25 - 10 == 15
n
, oder? In diesem Fall können Sie0
dem Set hinzufügen und dann überprüfen, ob die Größe (jetzt) größer als istn
. Dies kann nur geschehen, wenn die Unterschiede alle ungleich Null und unterschiedlich sind.HashSet.contains
ist in den meisten Fällen naheO(1)
und im schlimmsten FallO(n)
in Java 7 undO(log n)
in Java 8+ (es wurde verbessert, nachdem die Verkettung durch die Kollisionserkennung ersetzt wurde). Wenn ich das Set mit dem0
für die Prüfung hinzugefügten zurückgeben darf , ist es zwar etwas besser für die Leistung, aber wenn ichset.remove(0);
im if anrufen muss , bin ich mir ziemlich sicher, dass die Leistung etwas gleich ist.Mathematica n = 11
quelle