Ver Mensaje Individual
  #11 (permalink)  
Antiguo 22/02/2016, 08:29
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 12 años, 7 meses
Puntos: 320
Respuesta: Combinaciones de números aleatorios que no se repitan

Revivo el tema porque me llego un mensaje privado con la siguiente consulta:
Cita:
¿Cual es el objetivo de la posición tope? De acuerdo a si la posición tope es menor o no a la posición del cartón dentro del array, vos buscas un nuevo numero para componer el cartón.
La parte del código a la que me refiero es la siguiente:
Código PHP:
Ver original
  1. $mc = $items_count_combinacion - $item_numero - 1;
  2. $nc = $cantidad_elementos - 1;  
  3. // Hasta que posición le corresponde este elemento.
  4. $posicion_tope += (Factorial::calc($mc) / (Factorial::calc($nc) * Factorial::calc($mc - $nc)));
  5.  
  6. if($posicion_buscada <= $posicion_tope)
  7. {
  8. ...
El algoritmo funciona basado en combinaciones, consideremos un caso base para entenderlo mejor:
Supongamos que tienes los numero comprendidos entre el 1 y el 5 y quieres generar cartones con 3 numeros, solo podrias generar 10 cartones, puesto que la formula de combinacion es:
((m!) / (n! * (m-n)!)) = x
por lo tanto:
((5!) / (3! * (5-3)!)) = 10
Ahora bien, si quisieras generar todas las combinaciones posibles de forma "natural" tomarias el primer elemento y lo combinarias con todos los posibles:
[01]: 1, 2, 3
[02]: 1, 2, 4
[03]: 1, 2, 5
[04]: 1, 3, 4
[05]: 1, 3, 5
[06]: 1, 4, 5

Luego harias lo mismo con el segundo:
[07]: 2, 3, 4
[08]: 2, 3, 5
[09]: 2, 4, 5

Y con el tercero:
[10]: 3, 4, 5
Con el cuarto y quinto ya no hay ninguna combinacion posible para hacer sin repetir las anteriores.

Si en la funcion "carton" comentas esta parte del codigo:

Código PHP:
Ver original
  1. // Recorrer los todos elementos.
  2. //for($posicion=count($items)-1; $posicion; $posicion--)
  3. //{
  4. //    // Realizar los intercambios.
  5. //    $posicion_nueva = mt_rand(0, $posicion);
  6. //    $backup = $items[$posicion];
  7. //    $items[$posicion] = $items[$posicion_nueva];
  8. //    $items[$posicion_nueva] = $backup;
  9. //}
  10. //unset($posicion, $posicion_nueva, $backup);

Y la llamas asi:
Código PHP:
Ver original
  1. $items = range(1, 5);
  2. for($nro=1; $nro<=10; $nro++) {
  3.   echo "[$nro]: ".implode(", ", carton($items, 3, $nro))."<br>";
  4. }

Obtendras justamente ese mismo listado.

Observa que en cada posicion de numero dentro del carton (primera, segunda y tercera) en el orden listado son siempre crecientes hacia abajo y hacia la derecha, eso es muy importante.

Ahora bien, supongamos que quieres la combinacion 8:

Código PHP:
Ver original
  1. echo "[8]: ".implode(", ", carton($items, 3, 8))."<br>";

Que es:

[08]: 2, 3, 5

Para saber cuales son los numeros que la componen y teniendo en cuenta el punto anterior, debemos encontrar para cada numero posible (1, 2, 3, 4, 5) cual es la posicion tope en la que aparece, puedes agregar un echo antes en este lugar para observar como funciona:

Código PHP:
Ver original
  1. // Hasta que posicion le corresponde este elemento.
  2. $posicion_tope += (Factorial::calc($mc) / (Factorial::calc($nc) * Factorial::calc($mc - $nc)));
  3. $item = array_shift($items);
  4. $items_count--;
  5.  
  6. echo "Item: $item; Tope: $posicion_tope; Buscada: $posicion_buscada;<br>";
  7.  
  8. // Si la posicion buscada es menor al tope que le corresponde al elemento.
  9. if($posicion_buscada <= $posicion_tope)
  10. {

Para entender mejor que es lo que esta haciendo voy a comentar cada linea de la salida:
Item: 1; Tope: 6; Buscada: 1; // Hasta la combinacion 6 tienen un 1 como primer elemento.
Item: 2; Tope: 3; Buscada: 1; // Hasta la combinacion 3 tienen un 2 como segundo elemento.
Item: 3; Tope: 1; Buscada: 1; // Hasta la combinacion 1 tienen un 3 como tercer elemento.
[1]: 1, 2, 3 // La combinacion 1 se forma con los items donde Buscada <= Tope.
Item: 1; Tope: 6; Buscada: 2; // Hasta la combinacion 6 tienen un 1 como primer elemento.
Item: 2; Tope: 3; Buscada: 2; // Hasta la combinacion 3 tienen un 2 como segundo elemento.
Item: 3; Tope: 1; Buscada: 2; // Hasta la combinacion 1 tienen un 3 como tercer elemento.
Item: 4; Tope: 2; Buscada: 2; // Hasta la combinacion 2 tienen un 4 como tercer elemento.
[2]: 1, 2, 4 // La combinacion 2 se forma con los items donde Buscada <= Tope.
Item: 1; Tope: 6; Buscada: 3; // Hasta la combinacion 6 tienen un 1 como primer elemento.
Item: 2; Tope: 3; Buscada: 3; // Hasta la combinacion 3 tienen un 2 como segundo elemento.
Item: 3; Tope: 1; Buscada: 3; // Hasta la combinacion 1 tienen un 3 como tercer elemento.
Item: 4; Tope: 2; Buscada: 3; // Hasta la combinacion 2 tienen un 4 como tercer elemento.
Item: 5; Tope: 3; Buscada: 3; // Hasta la combinacion 3 tienen un 5 como tercer elemento.
[3]: 1, 2, 5 // La combinacion 3 se forma con los items donde Buscada <= Tope.
// ...

Y asi sigue de la misma manera con los demas.
__________________
Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios