Entrada: dos enteros n y k dados en cualquier forma que sea conveniente para su código
Salida Una secuencia aleatoria no decreciente de k enteros, cada uno en el rango de 1 a n. La muestra debe elegirse uniformemente entre todas las secuencias no decrecientes de k enteros con enteros en el rango de 1 a n.
La salida puede estar en cualquier formato razonable que considere conveniente.
Puede usar cualquier generador pseudoaleatorio que proporcione su biblioteca / idioma favorito.
Podemos suponer que los enteros n, k> 0.
Ejemplo
Digamos n, k = 2. Las secuencias no decrecientes son
1,1
1,2
2,2
Cada secuencia debe tener una probabilidad de 1/3 de salida.
Restricción
Su código debe ejecutarse en no más de unos segundos para k = 20 yn = 100.
Lo que no funciona
Si solo muestra cada número entero al azar del rango 1 a ny luego ordena la lista, no obtendrá una distribución uniforme.
fuente
Respuestas:
En realidad ,
1412 bytesEsta respuesta se basa en respuesta 05AB1E de Emigna y las respuestas en esta pregunta Math.SE . Sugerencias de golf bienvenidas! Pruébalo en línea!
Ungolfing
fuente
Python, 89 bytes
Generar una secuencia creciente en lugar de una no decreciente sería sencillo: esto es solo un subconjunto aleatorio de
k
números entre1
yn
, ordenados.Pero, podemos convertir una secuencia creciente en una no decreciente reduciendo cada espacio entre números consecutivos en 1. Entonces, un espacio de 1 se convierte en un espacio de 0, haciendo números iguales. Para hacerlo, disminuya el
i
'valor más grande eni
Para que el resultado sea de
1
an
, la entrada debe ser de1
an+k-1
. Esto proporciona una biyección entre secuencias no decrecientes de números entre1
yn
, a secuencias crecientes entre1
yn+k-1
. La misma biyección se usa en el argumento de barras y estrellas para contar tales secuencias.El código usa la función python
random.sample
, que tomak
muestras sin reemplazo de la lista de entrada. Ordenarlo da la secuencia creciente.fuente
import*
ahorrar 1 byte)05AB1E , 13 bytes
Pruébalo en línea!
Explicación
fuente
Python, 87 bytes
La probabilidad de que
n
se incluya el valor máximo posible es igualk/(n+k-1)
. Para incluirlo, colóquelo al final de la lista y disminuya los números necesarios restantesk
. Para excluirlo, disminuya el límite superiorn
. Luego, recurse hasta que no se necesiten más valores (k==0
).Python
random
no parece tener incorporado una variable de Bernoulli: 1 con alguna probabilidad, y 0 en caso contrario. Entonces, esto verifica si un valor aleatorio entre 0 y 1 generado porrandom
cae por debajok/(n+k-1)
. Python 2 sería la relación como la división de flotación, por lo que en su lugar se multiplican por el denominador:k>random()*(n+k-1)
.fuente
numpy.random
, que es demasiado largo.JavaScript (Firefox 30+), 74 bytes
Explicación
La excelente respuesta de Python de xnor contiene un muy buen resumen de cómo / por qué funciona la técnica utilizada aquí. El primer paso es crear el rango [1, 2, ..., n + k - 1] :
A continuación, debemos tomar k elementos aleatorios de este rango. Para hacer esto, debemos seleccionar cada elemento con probabilidad s / q , donde s es la cantidad de elementos que aún se necesitan y q es la cantidad de elementos que quedan en el rango. Como estamos usando una comprensión de matriz, esto es bastante fácil:
Esto nos da una secuencia creciente de números distribuidos uniformemente . Esto se puede solucionar restando el número de elementos j que hemos encontrado previamente:
Finalmente, almacenando k en j , podemos incorporar
k--
a la expresión y guardar algunos bytes:fuente
TI-BASIC, 54 bytes
Sigue la lógica de xnor, con una pequeña advertencia. Teóricamente podríamos afeitar un byte haciendo algo como esto:
Pero rand (está reservado para crear una lista de números aleatorios, por lo que no podríamos hacer la multiplicación implícita deseada para guardar un byte.
Esto debería ejecutarse decentemente rápido en un 84+ por restricción, pero lo comprobaré para asegurarme cuando pueda.
fuente
PHP,
777573 bytesCorre así:
Explicación
Ajustes
end()
llamada y establecer$argv[2]
en$k
lugar para acortar el acceso a los argumentos$i
cada iteraciónfuente