À propos de la série
Tout d'abord, vous pouvez traiter cela comme n'importe quel autre défi de golf de code et y répondre sans vous soucier de la série. Cependant, il existe un classement pour tous les défis. Vous pouvez trouver le classement avec plus d'informations sur la série dans le premier post .
Bien que j'ai un tas d'idées alignées pour la série, les défis futurs ne sont pas encore gravés dans le marbre. Si vous avez des suggestions, faites-le moi savoir sur le post sandbox correspondant .
Trou 3: partitions entières
Il est temps d'augmenter un peu la difficulté.
Une partition d'un entier positif n
est définie comme un ensemble multiple d'entiers positifs qui se résument à n
. Par exemple, si n = 5
, les partitions suivantes existent:
{1,1,1,1,1}
{2,1,1,1}
{2,2,1}
{3,1,1}
{3,2}
{4,1}
{5}
Notez que ce sont des multisets, donc il n'y a pas d'ordre {3,1,1}
, {1,3,1}
et ils {1,1,3}
sont tous considérés comme identiques.
Votre tâche est, étant donné n
, de générer une partition aléatoire de n
. Voici les règles détaillées:
La répartition des cloisons produites doit être uniforme . Autrement dit, dans l'exemple ci-dessus, chaque partition doit être renvoyée avec une probabilité 1/7.
Bien sûr, en raison des limites techniques des PRNG, une uniformité parfaite sera impossible. Aux fins d'évaluer l'uniformité de votre soumission, les opérations suivantes seront considérées comme produisant des distributions parfaitement uniformes:
- Obtention d'un numéro à partir d'un PRNG (sur n'importe quelle plage), qui est documenté comme étant (approximativement) uniforme.
- Mapper une distribution uniforme sur un ensemble de nombres plus grand sur un ensemble plus petit via modulo ou multiplication (ou une autre opération qui distribue les valeurs uniformément). L'ensemble plus grand doit contenir au moins 1024 fois autant de valeurs possibles que l'ensemble plus petit.
Étant donné que les partitions sont des ensembles multiples, vous pouvez les renvoyer dans n'importe quel ordre, et cet ordre n'a pas à être cohérent. Cependant, aux fins de la distribution aléatoire, l'ordre est ignoré. Autrement dit, dans l'exemple ci-dessus
{3,1,1}
,{1,3,1}
et{1,1,3}
ensemble doivent avoir une probabilité de 1/7 d'être retourné.- Votre algorithme doit avoir un runtime déterministe. En particulier, vous ne pouvez pas générer de multisets aléatoires et les rejeter s'ils ne correspondent pas
n
. - La complexité temporelle de votre algorithme doit être polynomiale
n
. En particulier, vous ne pouvez pas simplement générer toutes les partitions et en sélectionner une au hasard (car le nombre de partitions croît de façon exponentielle avecn
). Vous pouvez supposer que le PRNG que vous utilisez peut renvoyer des valeurs uniformément réparties en O (1) par valeur. - Vous ne devez utiliser aucune fonction intégrée qui résout cette tâche.
Vous pouvez écrire un programme complet ou une fonction et prendre une entrée via STDIN ou l'alternative la plus proche, l'argument de ligne de commande ou l'argument de fonction et produire une sortie via la valeur de retour ou en imprimant vers STDOUT (ou l'alternative la plus proche).
Vous pouvez supposer que n ≤ 65
(tel que le nombre de partitions est inférieur à 2 21 ). La sortie peut être dans n'importe quelle liste ou format de chaîne pratique et sans ambiguïté.
Si vous soumettez une fonction, veuillez également envisager de fournir un petit programme de test qui appelle la fonction plusieurs fois et imprime les résultats. Ce n'est pas grave si les paramètres doivent être modifiés dans le code. C'est juste pour que les gens puissent vérifier que la solution est au moins approximativement uniforme.
Il s'agit du code golf, donc la soumission la plus courte (en octets) l'emporte. Et bien sûr, la soumission la plus courte par utilisateur entrera également dans le classement général de la série.
Classement
Le premier post de la série génère un classement.
Pour vous assurer que vos réponses s'affichent, veuillez commencer chaque réponse par un titre, en utilisant le modèle Markdown suivant:
# Language Name, N bytes
où N
est la taille de votre soumission. Si vous améliorez votre score, vous pouvez conserver les anciens scores dans le titre, en les rayant. Par exemple:
# Ruby, <s>104</s> <s>101</s> 96 bytes
(La langue n'est pas actuellement affichée, mais l'extrait de code l'exige et l'analyse, et je pourrai ajouter un classement par langue à l'avenir.)
la source
u/\. y
bientôt obtenir quelque chose comme J ?GolfScript, 90 octets
Démo en ligne
Il s'agit d'une adaptation de mon code de comptage de partition (plus simple) qui, au lieu de simplement suivre un compte, suit à la fois un compte et un élément uniformément sélectionné parmi les éléments comptés.
Comparaison côte à côte des deux:
Différences:
~
est que c'est un programme plutôt qu'un extrait de code.[1.]
remplacement1
correspond au changement de ce qui est suivi.{(\{)}%+}%
incréments supplémentaires incrémentent chaque élément de cette partition et les{1+}%
ajouts1
à la partition.0
devient[0]
(joué au golf1,
) dans le cadre du changement de ce qui est suivi, mais parce qu'il doit rester un tableau lorsqu'il est ajouté à un autre, il a besoin de plus[ ]
.{+}*
devient une sélection pondérée à partir des partitions, combinée à une somme de leur nombre.(;`
supprime le nombre de la sortie et place la partition dans un format agréable.Cadre de test
Modifiez le 7000 initial si vous souhaitez exécuter un nombre différent d'essais. Notez que c'est beaucoup trop lent pour une démo en ligne.
la source
Java,
285267 octetsIl s'agit de la même méthode que la réponse de TheBestOne, mais elle utilise un tableau simple au lieu d'une carte. De plus, au lieu de renvoyer la partition aléatoire en tant que a
List
, il les imprime sur la console.Voici un programme de test qui l'exécute 100000 fois. Pour l'exemple
n=5
, tous les sets étaient à 0,64% d'un 1/7 parfait lors de ma dernière course.la source
Math.min
appel vers(k<n?k:n)
, vous pouvez aller plus loin en abandonnant entièrement et juste faire deux contrôles:b<k&b++<n
. Vous pouvez également facilement abandonner lan>0
partie de la boucle conditionnelle (carn>0&b<n
réduit àb<n
quandb
est garanti non négatif).int
déclaration séparée .CJam,
6456 octetsVous pouvez le tester avec ce script:
Explication
la source
Pyth, 64 octets
Utilise /programming//a/2163753/4230423 sauf que a) Pas de cache puisque Pyth mémorise automatiquement, b) Imprime chacun au lieu de l'ajouter à la liste, et c) est traduit en Pyth.
Je posterai une explication de cela quand j'aurai le temps, mais voici le code python correspondant:
Edit: j'ai finalement réussi à faire l'explication:
la source
Octave, 200
Non golfé:
Construisez une matrice carrée où chaque cellule (m, n) reflète le nombre de partitions
m
dont le plus grand nombre estn
, selon l'extrait de Knuth @feersum si gentiment cité. Par exemple,5,2
nous donne 2 car il y a deux partitions valides2,2,1
et2,1,1,1
.6,3
nous donne 3 pour3,1,1,1
,3,2,1
et3,3
.Nous pouvons maintenant trouver de façon déterministe la pème partition. Ici, nous générons
p
un nombre aléatoire, mais vous pouvez modifier légèrement le script, toutp
comme un paramètre:Nous pouvons maintenant montrer de façon déterministe que chaque résultat dépend uniquement de p:
Ainsi, pour revenir à l'original où p est généré de façon aléatoire, nous pouvons être assurés que chaque résultat est également probable.
la source
(2,2,1)
et(2,1,1,1,1)
(puisque les deux que vous avez répertoriées ont des nombres supérieurs à2
).2
. Je voulais dire ce dernier.R, 198 octets
Non golfé:
Il suit la même structure que la grande solution de @ dcsohl dans Octave , et est donc également basé sur le extrait de Knuth publié par @feersum.
J'éditerai cela plus tard si je peux trouver une solution plus créative dans R. En attendant, toute contribution est bien sûr la bienvenue.
la source
Java, 392 octets
Appeler avec
a(n)
. Renvoie unList
deInteger
sDentelé:
Adapté de /programming//a/2163753/4230423 et golfé
Comment cela fonctionne: Nous pouvons calculer combien de partitions d'un entier n il y a en temps O ( n 2 ). Comme effet secondaire, cela produit un tableau de taille O ( n 2 ) que nous pouvons ensuite utiliser pour générer la k ème partition de n , pour tout entier k , dans O ( n ).
Soit donc total = le nombre de partitions. Choisissez un nombre aléatoire k de 0 au total - 1. Générez la k ème partition.
Comme d'habitude , les suggestions sont les bienvenues :)
la source
Python 2, 173 octets
Fait récursivement un dictionnaire
d
, avec des clésk
représentant une paire(n,m)
park=67*n+m
(en utilisant la garantien<=65
). L'entrée est le tuple du nombre de partition den
dansm
parties, et une telle partition aléatoire. Les décomptes sont calculés par la formule récursive (merci à feersum de l'avoir signalé)f(n,m) = f(n-1,m-1) + f(n,n-m)
,et la partition aléatoire est mise à jour en choisissant l'une des deux de ses branches avec une probabilité proportionnelle à son comptage. La mise à jour se fait en ajoutant se fait en ajoutant un
1
pour la première branche et en incrémentant chaque élément pour la seconde.J'ai eu beaucoup de mal à obtenir des valeurs hors limites
m
etn
à donner des comptes de zéro. Au début, j'ai utilisé un dictionnaire par défaut à un nombre de 0 et une liste vide. Ici, j'utilise une liste et je la remplis avec cette entrée par défaut à la place. Les indices négatifs provoquent la lecture de la liste depuis sa fin, ce qui donne une entrée par défaut qui n'est rien près de la fin comme jamais atteinte, et les bouclages ne touchent qu'une région oùm>n
.la source
80386 code machine, 105 octets
Hexdump du code:
En fonction de C:
void random_partition(int n, int result[]);
. Il renvoie le résultat sous la forme d'une liste de nombres dans le tampon fourni; cela ne marque en aucun cas la fin de la liste, mais l'utilisateur peut découvrir la fin en accumulant les nombres - la liste se termine lorsque la somme est égale àn
.Comment utiliser (dans Visual Studio):
Exemple de sortie (avec n = 64):
Cela demande beaucoup d'explications ...
Bien sûr, j'ai utilisé l'algorithme que tout le monde a également utilisé; il n'y avait pas de choix avec l'exigence de complexité. Je n'ai donc pas besoin d'expliquer trop l'algorithme. En tous cas:
Je dénote par
f(n, m)
le nombre de partitionnements d'n
éléments utilisant des parties pas plus grand quem
. Je les stocke dans un tableau 2D (déclaré en C commef[65][64]
), où se trouve le premier indexn
et le secondm-1
. J'ai décidé que soutenirn=65
était trop difficile, alors abandonné ...Voici le code C qui calcule ce tableau:
Ce code a un style obscurci, il peut donc être facilement converti en langage assembleur. Il calcule les éléments jusqu'à
f(n, n)
, qui est le nombre de partitionnements d'n
éléments. Lorsque ce code est terminé, la variable temporairec
contient le nombre nécessaire, qui peut être utilisé pour sélectionner un partitionnement aléatoire:Plus tard, ce
index
est converti au format requis (liste de nombres) à l'aide de la table générée.Ce code est également optimisé pour la conversion en langage assembleur. Il y a un petit "bug": si le partitionnement ne contient aucun
1
nombre à la fin, la dernière boucle rencontren = 0
et génère un1
élément inutile . Cela ne fait pas de mal, cependant, car le code d'impression suit la somme du nombre et n'imprime pas ce nombre superflu.Lorsqu'il est converti en assemblage en ligne, ce code ressemble à ceci:
Quelques choses amusantes à noter:
rdrand
instruction)ah
, ce qui me donne une multiplication automatique par 256. Pour en profiter, j'ai sacrifié le support den = 65
. J'espère que je peux être excusé pour ce péché ...L'allocation d'espace sur la pile est effectuée en soustrayant 0x4100 du registre de pointeur de pile
esp
. Il s'agit d'une instruction de 6 octets! En rajoutant ce numéro, j'ai réussi à le faire en 5 octets:Lors du débogage de cette fonction dans MS Visual Studio, j'ai découvert qu'elle se bloque lorsqu'elle écrit des données dans l'espace qu'elle a alloué sur la pile! Après quelques recherches, j'ai découvert une sorte de protection contre le dépassement de pile: le système d'exploitation semble n'allouer qu'une plage très limitée d'adresses virtuelles pour la pile; si une fonction accède à une adresse trop éloignée, le système d'exploitation suppose qu'il s'agit d'un dépassement et tue le programme. Cependant, si une fonction possède de nombreuses variables locales, le système d'exploitation fait un peu de "magie" supplémentaire pour la faire fonctionner. Je dois donc appeler une fonction vide qui a un grand tableau alloué sur la pile. Après le retour de cette fonction, des pages de VM de pile supplémentaires sont allouées et peuvent être utilisées.
la source