Über die Serie
Zunächst einmal können Sie dies wie jede andere Code-Golf-Herausforderung behandeln und beantworten, ohne sich Gedanken über die Serie zu machen. Es gibt jedoch eine Rangliste für alle Herausforderungen. Sie finden die Rangliste zusammen mit einigen weiteren Informationen über die Serie im ersten Beitrag .
Obwohl ich eine Menge Ideen für die Serie habe, sind die zukünftigen Herausforderungen noch nicht in Stein gemeißelt. Wenn Sie Vorschläge haben, teilen Sie mir dies bitte auf dem entsprechenden Sandbox-Post mit .
Loch 3: Ganzzahlige Partitionen
Zeit, den Schwierigkeitsgrad etwas zu erhöhen.
Eine Partition einer positiven Ganzzahl n
ist definiert als ein Multiset von positiven Ganzzahlen, die sich summieren n
. Als Beispiel n = 5
existieren die folgenden Partitionen:
{1,1,1,1,1}
{2,1,1,1}
{2,2,1}
{3,1,1}
{3,2}
{4,1}
{5}
Beachten Sie, dass diese Multimengen sind, so gibt es keine Ordnung zu ihnen {3,1,1}
, {1,3,1}
und {1,1,3}
sind alle identisch betrachtet.
Ihre Aufgabe ist es n
, eine zufällige Partition von zu generieren n
. Hier sind die detaillierten Regeln:
Die Verteilung der produzierten Partitionen muss gleichmäßig sein . Das heißt, im obigen Beispiel sollte jede Partition mit einer Wahrscheinlichkeit von 1/7 zurückgegeben werden.
Aufgrund der technischen Einschränkungen von PRNGs ist eine perfekte Gleichmäßigkeit natürlich nicht möglich. Um die Gleichmäßigkeit Ihrer Einreichung zu beurteilen, werden die folgenden Vorgänge als perfekt gleichmäßige Verteilungen ergebend angesehen:
- Beziehen einer Nummer von einem PRNG (über einen beliebigen Bereich), von dem dokumentiert wird, dass sie (ungefähr) einheitlich ist.
- Abbildung einer gleichmäßigen Verteilung über eine größere Menge von Zahlen auf eine kleinere Menge durch Modulo oder Multiplikation (oder eine andere Operation, die Werte gleichmäßig verteilt). Die größere Menge muss mindestens das 1024-fache der möglichen Werte der kleineren Menge enthalten.
Da es sich bei den Partitionen um Multisets handelt, können Sie sie in beliebiger Reihenfolge zurückgeben, und diese Reihenfolge muss nicht konsistent sein. Für die zufällige Verteilung wird die Reihenfolge jedoch ignoriert. Das heißt, in dem obigen Beispiel
{3,1,1}
,{1,3,1}
und{1,1,3}
zusammen müssen eine Wahrscheinlichkeit von 1/7 haben zurückgegeben werden.- Ihr Algorithmus muss eine deterministische Laufzeit haben. Insbesondere können Sie keine zufälligen Multisets generieren und ablehnen, wenn sie nicht zusammengerechnet werden
n
. - Die Zeitkomplexität Ihres Algorithmus muss polynomiell sein
n
. Insbesondere können Sie nicht einfach alle Partitionen generieren und eine zufällige auswählen (da die Anzahl der Partitionen mit exponentiell wächstn
). Sie können davon ausgehen, dass der von Ihnen verwendete PRNG gleichmäßig verteilte Werte in O (1) pro Wert zurückgeben kann. - Sie dürfen keine eingebaute Funktion verwenden, die diese Aufgabe löst.
Sie können ein vollständiges Programm oder eine Funktion schreiben und Eingaben über STDIN oder die nächstgelegene Alternative, ein Befehlszeilenargument oder ein Funktionsargument vornehmen und Ausgaben über den Rückgabewert oder durch Drucken an STDOUT (oder die nächstgelegene Alternative) erzeugen.
Sie können davon ausgehen, dass n ≤ 65
(so dass die Anzahl der Partitionen weniger als 2 21 ist ). Die Ausgabe kann in einem beliebigen praktischen, eindeutigen Listen- oder Zeichenfolgenformat erfolgen.
Wenn Sie eine Funktion einreichen, sollten Sie auch ein kleines Testprogramm bereitstellen, das die Funktion mehrmals aufruft und die Ergebnisse druckt. Es ist in Ordnung, wenn die Parameter im Code angepasst werden müssen. Dies ist nur so, dass die Leute überprüfen können, ob die Lösung zumindest annähernd einheitlich ist.
Dies ist Codegolf, daher gewinnt die kürzeste Übermittlung (in Bytes). Und natürlich wird die kürzeste Einreichung pro Benutzer auch in die Gesamt-Bestenliste der Serie aufgenommen.
Bestenliste
Der erste Beitrag der Serie generiert eine Rangliste.
Um sicherzustellen, dass Ihre Antworten angezeigt werden, beginnen Sie jede Antwort mit einer Überschrift. Verwenden Sie dazu die folgende Markdown-Vorlage:
# Language Name, N bytes
Wo N
ist die Größe Ihres Beitrags? Wenn Sie Ihren Score zu verbessern, Sie können alte Rechnungen in der Überschrift halten, indem man sich durch das Anschlagen. Zum Beispiel:
# Ruby, <s>104</s> <s>101</s> 96 bytes
(Die Sprache wird derzeit nicht angezeigt, das Snippet erfordert sie jedoch und analysiert sie. Ich füge möglicherweise in Zukunft eine Bestenliste nach Sprachen hinzu.)
quelle
u/\. y
?GolfScript, 90 Bytes
Online-Demo
Dies ist eine Anpassung meines (einfacheren) Partitionszählcodes, der anstelle einer bloßen Verfolgung einer Zählung sowohl eine Zählung als auch ein einheitlich ausgewähltes der gezählten Elemente verfolgt.
Side-by-Side-Vergleich der beiden:
Unterschiede:
~
ist, weil dies eher ein Programm als ein Ausschnitt ist.[1.]
Ersetzen1
entspricht der Änderung des Verfolgten.{(\{)}%+}%
erhöht jedes Element in dieser Partition und das{1+}%
fügt1
der Partition hinzu.0
wird[0]
(golfen1,
) als Teil der Änderung dessen, was verfolgt wird, aber weil es ein Array bleiben muss, wenn es einem anderen vorangestellt wird, braucht es das Extra[ ]
.{+}*
wird zu einer gewichteten Auswahl aus den Partitionen, kombiniert mit einer Summierung ihrer Anzahl.(;`
entfernt die Zählung von dem Ausgang und legt die Partition in ein schönes Format.Test Framework
Optimieren Sie die ersten 7000, wenn Sie eine andere Anzahl von Versuchen ausführen möchten. Beachten Sie, dass dies für eine Online-Demo viel zu langsam ist.
quelle
Java,
285267 BytesDies ist die gleiche Methode wie die Antwort von TheBestOne, verwendet jedoch ein einfaches Array anstelle einer Karte. Anstatt die zufällige Partition als "a" zurückzugeben
List
, werden sie auch auf der Konsole gedruckt.Unten ist ein Testprogramm, das es 100000-mal ausführt. Für das Beispiel
n=5
lagen alle Sätze bei meinem letzten Lauf innerhalb von 0,64% eines perfekten 1/7.quelle
Math.min
Anruf nach unten zu(k<n?k:n)
, können Sie noch weiter gehen , indem sie es ganz Notwasserung und zwei Kontrollen nur tun:b<k&b++<n
. Sie können denn>0
Teil der Schleife auch problemlos als bedingt kennzeichnen (da ern>0&b<n
auf denb<n
Zeitpunkt reduziertb
wird, der garantiert nicht negativ ist).int
Erklärung los .CJam,
6456 BytesSie können es mit diesem Skript testen:
Erläuterung
quelle
Pyth, 64 Bytes
Verwendet /programming//a/2163753/4230423, mit der Ausnahme, dass a) kein Cache vorhanden ist, da Pyth automatisch ein Memo erstellt, b) jeder druckt, anstatt an die Liste anzuhängen, und c) in Pyth übersetzt wird.
Ich werde eine Erklärung dazu veröffentlichen, wenn ich Zeit habe, aber hier ist der entsprechende Python-Code:
Edit: Ich bin endlich dazu gekommen, die Erklärung zu machen:
quelle
Oktave, 200
Ungolfed:
Konstruieren Sie eine quadratische Matrix, in der jede Zelle (m, n) die Anzahl der Partitionen widerspiegelt,
m
deren größte Anzahln
nach dem so freundlich zitierten Knuth-Extrakt @feersum ist. Zum Beispiel5,2
gibt uns 2, weil es zwei gültige Partitionen2,2,1
und gibt2,1,1,1
.6,3
gibt uns 3 für3,1,1,1
,3,2,1
und3,3
.Wir können nun deterministisch die p-te Partition finden. Hier erzeugen wir
p
eine Zufallszahl, aber Sie können das Skript leicht ändern, sop
ist ein Parameter:Wir können nun deterministisch zeigen, dass jedes Ergebnis ausschließlich von p abhängt:
Wenn wir also zum Original zurückkehren, in dem p zufällig generiert wird, können wir sicher sein, dass jedes Ergebnis gleich wahrscheinlich ist.
quelle
(2,2,1)
und sein(2,1,1,1,1)
(da die beiden von Ihnen aufgelisteten Nummern größer sind als2
)?2
. Ich meinte letzteres.R, 198 Bytes
Ungolfed:
Es folgt der gleichen Struktur wie @ dcsohls großartige Lösung in Octave und basiert daher auch auf dem von @feersum veröffentlichten Knuth-Extrakt .
Ich bearbeite das später, wenn ich eine kreativere Lösung in R finden kann. In der Zwischenzeit ist jede Eingabe natürlich willkommen.
quelle
Java, 392 Bytes
Mit anrufen
a(n)
. Gibt aList
vonInteger
s zurückEingerückt:
Adaptiert von /programming//a/2163753/4230423 und golfen
So funktioniert es: Wir können berechnen, wie viele Partitionen einer ganzen Zahl n in der O ( n 2 ) -Zeit vorhanden sind . Als Nebeneffekt erzeugt dies eine Tabelle der Größe O ( n 2 ), die wir dann verwenden können, um die k- te Partition von n für eine beliebige ganze Zahl k in der O ( n ) -Zeit zu erzeugen .
Also sei total = die Anzahl der Partitionen. Wählen Sie eine Zufallszahl k von 0 bis total - 1. Generieren Sie die k- te Partition.
Wie üblich , Vorschläge sind willkommen :)
quelle
Python 2, 173 Bytes
Erstellt rekursiv ein Wörterbuch
d
mit Schlüsseln,k
die ein Paar darstellen,(n,m)
indemk=67*n+m
(unter Verwendung der Garantien<=65
). Der Eintrag ist das Tupel der Anzahl der Partitionenn
inm
Teile und eine zufällige solche Partition. Die Zählungen werden nach der rekursiven Formel berechnet (danke an feersum für den Hinweis)f(n,m) = f(n-1,m-1) + f(n,n-m)
,und die zufällige Partition wird aktualisiert, indem einer der beiden Zweige mit einer Wahrscheinlichkeit ausgewählt wird, die proportional zu seiner Anzahl ist. Die Aktualisierung erfolgt durch Hinzufügen von a
1
für den ersten Zweig und Inkrementieren jedes Elements für den zweiten Zweig.Ich hatte große Probleme, Werte von
m
undn
Null zu ermitteln. Zuerst habe ich ein Wörterbuch verwendet, das standardmäßig 0 und eine leere Liste enthält. Hier verwende ich eine Liste und fülle sie stattdessen mit diesem Standardeintrag auf. Negative Indizes bewirken, dass die Liste von ihrem Ende gelesen wird, was bedeutet, dass ein Standardeintrag nicht mehr in der Nähe des Endes ist, als jemals erreicht, und dass Umgehungen nur einen Bereich berühren, in demm>n
.quelle
80386 Maschinencode, 105 Bytes
Hexdump des Codes:
Als C - Funktion:
void random_partition(int n, int result[]);
. Das Ergebnis wird als Liste von Zahlen im angegebenen Puffer zurückgegeben. es markiert in keiner Weise das Ende der Liste, aber der Benutzer kann das Ende durch Akkumulieren der Zahlen erkennen - die Liste endet, wenn die Summe gleich istn
.Wie benutzt man (in Visual Studio):
Beispielausgabe (mit n = 64):
Dies erfordert viele Erklärungen ...
Natürlich habe ich den Algorithmus verwendet, den auch alle anderen verwendet haben. Es gab keine andere Wahl als die Komplexität. Deshalb muss ich den Algorithmus nicht zu viel erklären. Sowieso:
Ich bezeichne durch
f(n, m)
die Anzahl der Partitionen vonn
Elementen mit Teilen nicht größer alsm
. Ich speichere sie in einem 2-D-Array (in C als deklariertf[65][64]
), wobei der erste Indexn
und der zweite Index istm-1
. Ich entschied, dass das Unterstützenn=65
zu viel Mühe war, also gab ich es auf ...Hier ist C-Code, der diese Tabelle berechnet:
Dieser Code hat einen etwas verschleierten Stil, sodass er leicht in die Assemblersprache konvertiert werden kann. Es berechnet die Elemente bis
f(n, n)
, dh die Anzahl der Partitionen vonn
Elementen. Wenn dieser Code fertig ist,c
enthält die temporäre Variable die erforderliche Nummer, mit der eine zufällige Partitionierung ausgewählt werden kann:Diese
index
wird später anhand der generierten Tabelle in das gewünschte Format (Nummernliste) konvertiert.Dieser Code ist auch für die Konvertierung in Assemblersprache optimiert. Es gibt einen kleinen "Bug": wenn die Partitionierung keine enthält
1
am Ende Nummer , trifft die letzte Schleife aufn = 0
ein nicht benötigtes1
Element und gibt es aus . Es tut jedoch nicht weh, weil der Druckcode die Summe der Zahlen verfolgt und diese fremde Zahl nicht druckt.Bei der Konvertierung in eine Inline-Assembly sieht dieser Code folgendermaßen aus:
Einige lustige Dinge zu beachten:
rdrand
Anweisung)ah
, was mir eine automatische Multiplikation mit 256 ermöglicht. Um dies zu nutzen, habe ich die Unterstützung für geopfertn = 65
. Ich hoffe, ich kann für diese Sünde entschuldigt werden ...Das Zuweisen von Speicherplatz auf dem Stapel wird ausgeführt, indem 0x4100 vom Stapelzeigerregister subtrahiert wird
esp
. Dies ist eine 6-Byte-Anweisung! Als ich diese Zahl wieder hinzufügte, schaffte ich es in 5 Bytes:Beim Debuggen dieser Funktion in MS Visual Studio habe ich festgestellt, dass sie abstürzt, wenn Daten in den Speicher geschrieben werden, den sie auf dem Stapel zugewiesen hat! Nach einigem Stöbern entdeckte ich eine Art Stapelüberlaufschutz: Das Betriebssystem weist dem Stapel anscheinend nur einen sehr begrenzten Bereich virtueller Adressen zu. Wenn eine Funktion auf eine zu weit entfernte Adresse zugreift, geht das Betriebssystem von einem Überlauf aus und beendet das Programm. Wenn eine Funktion jedoch viele lokale Variablen enthält, führt das Betriebssystem eine zusätzliche "Magie" aus, damit sie funktioniert. Ich muss also eine leere Funktion aufrufen, die ein großes Array auf dem Stack hat. Nachdem diese Funktion zurückgegeben wurde, werden zusätzliche Stapel-VM-Seiten zugewiesen und können verwendet werden.
quelle