2012-05-10 14 views
7

En mi algoritmo tengo dos valores que debo elegir al azar, pero cada uno debe elegirse un número predeterminado de veces.Elecciones aleatorias de dos valores

Hasta ahora mi solución es poner las opciones en un vector el número correcto de veces y luego mezclarlo. En C++:

// Example choices (can be any positive int) 
int choice1 = 3; 
int choice2 = 4; 

int number_of_choice1s = 5; 
int number_of_choice2s = 1; 

std::vector<int> choices; 
for(int i = 0; i < number_of_choice1s; ++i) choices.push_back(choice1); 
for(int i = 0; i < number_of_choice2s; ++i) choices.push_back(choice2); 
std::random_shuffle(choices.begin(), choices.end()); 

Entonces guardo un iterador a choices y cada vez que necesito uno nuevo aumento el iterador y agarrar ese valor.

Esto funciona, pero parece que podría haber una manera más eficiente. Como siempre sé cuántos de cada valor usaré, me pregunto si hay una forma más algorítmica de hacer esto, en lugar de simplemente almacenar los valores.

+0

Me quedaría con la solución de trabajo a menos que haya una buena razón para no hacerlo. ¿Está perfilado como un cuello de botella o algo así? – amit

+0

Hay un camino, pero sería menos claro y conciso. Me quedaría con esta técnica. –

+0

Realmente me gusta esta solución como es. Todas las otras soluciones que vienen a la mente (después de pensar durante unos 5 segundos) involucran generadores de números aleatorios. Pero dado que tiene un número predeterminado de cada opción, estas soluciones serían ineficaces ya que, en última instancia, tendrían que empezar a ignorar los valores una vez que su elección ya se hubiera producido la cantidad máxima de veces. (Es cierto que el método aleatorio es potencialmente un drenaje de CPU, pero al menos puede hacer que sea un tiempo de ejecución predecible, que no se puede hacer con las soluciones en las que estaba pensando) – gnomed

Respuesta

10

Está utilizando innecesariamente tanta memoria. Tiene dos variables:

int number_of_choice1s = 5; 
int number_of_choice2s = 1; 

Ahora simplemente RANDOMIZE:

int result = rand() % (number_of_choice1s + number_of_choice2s); 
if(result < number_of_choice1s) { 
    --number_of_choice1s; 
    return choice1; 
} else { 
    --number_of_choice2s; 
    return choice2; 
} 

Esta escalas muy bien dos millones de invocaciones al azar.

+0

Una vez que cualquiera de los contadores alcanza 0 puede cortocircuitar el resto del proceso –

+0

¿Cómo hay un sesgo? Esto simplemente parece una versión personalizada del algoritmo m de knuth n de Knuth - +1 de mí – BrokenGlass

+2

Pero tenga en cuenta que si su biblioteca estándar tiene una mala implementación 'rand' (p. Ej., Lineal congruente con un módulo pequeño), use'% ' así puede introducir sesgo. Además, 'RAND_MAX' puede ser tan pequeño como 32767 (el' rand' en la biblioteca estándar de Microsoft tiene esta propiedad) y perderá totalmente si tiene una gran cantidad de opciones para hacer. –

1

Se puede escribir esto un poco más simple:

std::vector<int> choices(number_of_choice1s, choice1); 
choices.resize(number_of_choice1s + number_of_choice2s, choice2); 
std::random_shuffle(choices.begin(), choices.end()); 
0

Una distribución aleatoria sesgada va a mantener algún tipo de orden sobre el conjunto resultante (la elección que fue recogido la mayoría tiene que ser recogido menos y menos posibilidades siguiente), que dan un resultado sesgado (especialmente si la cantidad de tiempo que tiene para elegir el primer valor es grande en comparación con el segundo valor, terminará con algo como esto {1,1,1,2,1,1 , 1,1,2}.

Aquí está el código, que se parece mucho al escrito por @Tomasz Nurkiewicz pero utilizando un simple par/impar que debería dar una probabilidad del 50/50 de elegir cualquiera de los dos. lues.

int result = rand(); 

if (result & 1 && number_of_choice1s > 0) 
{ 
number_of_choice1s--; 
return choice1; 
}else if (number_of_choice2s>0) 
{ 
number_of_choice2s--; 
return choice2; 
} 
else 
{ 
return -1; 
} 
Cuestiones relacionadas