Ver Mensaje Individual
  #6 (permalink)  
Antiguo 27/02/2015, 18:21
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 12 años
Puntos: 320
Respuesta: Combinaciones de números aleatorios que no se repitan

Gracias por sus respuestas, pero creo que no me exprese bien, tratare de explicarme un poco mejor.

El usuario da de alta cada tanto nuevos clientes, en el momento del alta, el sistema le asigna a ese cliente un cartón generado aleatoriamente que no debe estar asignado a ningún otro cliente previo.

En la base de datos, se guardan los clientes y los cartones que tiene asociado cada uno.

El problema es como generar un cartón QUE NO ESTE ASIGNADO A NINGÚN OTRO CLIENTE de los que ya están registrados.

Levantar a memoria todos los cartones registrados para luego armar uno nuevo, puede voltearme el server ya que van a ser muchísimos.

Se me ocurrió otra posibilidad que es muy viable y genérica, pero que no logro hacerla funcionar, la idea es esta:

Dado un conjunto de elementos cualquiera, se pueden obtener una lista de todas sus combinaciones de elementos de forma ordenada sin problemas, ahora, si pudiera obtener directamente una combinación de esa lista, sin calcular las demás, podría guardar el numero de carton del cliente como un entero comun, y luego al vuelo obtener la combinacion de numeros correspondiente.

El problema que tengo es que no logro que la funcion ande, ¿Me podrían dar una mano?
Código PHP:
Ver original
  1. <?php
  2.     function factorial($numero)
  3.     {
  4.         $fact = 1;
  5.         while($numero >= 1 && ($fact *= $numero--));
  6.         return $fact;
  7.     }
  8.    
  9.     function combinatoria($m, $n)
  10.     {
  11.         return (factorial($m) / (factorial($n) * factorial($m - $n)));
  12.     }
  13.    
  14.     // Esta funcion obtiene la combinacion de una posicion.
  15.     // Items es un array con los elementos
  16.     // $n el numero de elementos por carton
  17.     // $pos es la posicion que me interesa
  18.     function cartones($items, $n, $pos)
  19.     {
  20.         // Aca se guardan los items del carton
  21.         $combinacion = [];        
  22.         // Cuantos items hay
  23.         $m = count($items);
  24.                    
  25.         // Auxiliares
  26.         $base = 0;
  27.         $idx = -1;
  28.         // Mientras me falte algun elemento en la combinacion
  29.         while($n)
  30.         {
  31.             //echo "<hr>";
  32.             // Numero de combinaciones posibles
  33.             $posibles = combinatoria($m, $n);
  34.             // Para cada variacion de 1 elemento posible
  35.             for($nro=0; $nro<$m-$n+1; $nro++)
  36.             {
  37.                 // Desde donde arranca ese elemento
  38.                 $desde = $base + $posibles - combinatoria($m - $nro, $n);
  39.                 // Hasta donde termina ese elemento
  40.                 $hasta = $base + $posibles - combinatoria($m - $nro - 1, $n) - 1;
  41.  
  42.                 $idx++;
  43.                 //echo "Rango: $desde - $hasta | $pos<br>";
  44.                 // Si la posicion que busco esta dentro de ese rango
  45.                 // NOTA: La segunda parte, luego del or, esta puesta como parche, pero no le encuentro logica
  46.                 if(($pos >= $desde && $pos <= $hasta) || ($hasta < $desde && $pos == $desde))
  47.                 {  
  48.                     // Guardar el origen del grupo como punto de partida
  49.                     $base = $desde;
  50.                     //echo "Ok!<br>";
  51.                     // Agregar al carton el item correspondiente.
  52.                     $combinacion[] = $items[$idx];
  53.                     break;
  54.                 }          
  55.             }            
  56.             $m--;
  57.             $n--;          
  58.         }
  59.                
  60.         return $combinacion;
  61.     }
  62.     //var_dump(cartones(range(0, 9), 4, 34));
  63.    
  64.     // Tests
  65.     // Genero todas las combinaciones posibles de 9 elementos tomados de a 4 y los comparo con los de la funcion para ver cuales fallan
  66.     echo "<hr>";
  67.     $id = 0;
  68.     $fails = 0;
  69.     for($a=0; $a<=6; $a++)
  70.     {            
  71.         for($e=$a+1; $e<=9; $e++)
  72.         {
  73.             for($i=$e+1; $i<=9; $i++)
  74.             {
  75.                 for($o=$i+1; $o<=9; $o++)
  76.                 {
  77.                     $carton = cartones(range(0, 9), 4, $id);
  78.                     if($carton[0] != $a || $carton[1] != $e || $carton[2] != $i || $carton[3] != $o)
  79.                     {                        
  80.                         echo "$id -> [$a, $e, $i, $o] -> [$carton[0], $carton[1], $carton[2], $carton[3]]<br>";
  81.                         $fails++;
  82.                     }
  83.                     else
  84.                     {
  85.                         //echo "$id -> Ok!<br>";                        
  86.                     }
  87.                     $id++;
  88.                 }
  89.             }
  90.         }
  91.     }
  92.    
  93.     echo "Terminado! $fails Fallas";


Para que todo ande los test no deberia fallar ninguno, pero actualmente fallan 140 de 210.
No encuentro como hacerlo andar
__________________
Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios