2010-05-08 11 views
15

Soy bastante nuevo en PHP - programación en general. Así que, básicamente, lo que tengo que lograr es, crear una matriz de x cantidad de números (creados al azar) cuyo valor se suman a n:Crear números dentro de una matriz que se suman a una cantidad establecida

Digamos, tengo que crear 4 números que suman 30 . Solo necesito el primer conjunto de datos aleatorios. El 4 y el 30 son variables que el usuario establecerá.

Esencialmente algo así como

x = amount of numbers; 
n = sum of all x's combined; 

// create x random numbers which all add up to n; 

$row = array(5, 7, 10, 8) // these add up to 30 

Además, no se permiten duplicados y todos los números tienen que ser números enteros positivos.

Necesito los valores dentro de una matriz. He estado jugando con eso en algún momento, sin embargo, mi conocimiento es bastante limitado. Cualquier ayuda será apreciada.

+0

son duplicados permitido? – Gumbo

+0

No. Disculpe que voy a editar mi publicación. –

+3

* (relacionado) * http://en.wikipedia.org/wiki/Partition_%28number_theory%29 – Gordon

Respuesta

7

F Al principio, este es un problema realmente genial. Estoy casi seguro de que mi enfoque ni siquiera distribuye los números a la perfección, pero debería ser mejor que algunos de los otros enfoques aquí.

Decidí construir la matriz desde el número más bajo (y mezclarlos al final). Esto me permite elegir siempre un rango aleatorio que permita obtener resultados válidos. Como los números siempre deben estar aumentando, resolví el número más alto posible que garantiza que todavía exista una solución válida (es decir, si n = 4 y max = 31, si el primer número se seleccionó para ser 7, entonces no sería ser posible elegir números mayores que 7 de manera que la suma de 4 números sea igual a 31).

$n = 4; 
$max = 31; 
$array = array(); 

$current_min = 1; 
while($n > 1) { 
    //solve for the highest possible number that would allow for $n many random numbers 
    $current_max = floor(($max/$n) - (($n-1)/2)); 
    if($current_max < $current_min) throw new Exception("Can't use combination"); 
    $new_rand = rand($current_min, $current_max); //get a new rand 
    $max -= $new_rand; //drop the max 
    $current_min = $new_rand + 1; //bump up the new min 
    $n--; //drop the n 
    $array[] = $new_rand; //add rand to array 
} 
$array[] = $max; //we know what the last element must be 
shuffle($array); 

EDIT: Para valores grandes de $n que va a terminar con una gran cantidad de valores agrupados hacia el final de la matriz, ya que hay una buena probabilidad de que obtendrá un valor aleatorio cerca del valor máximo obligando al descansar para estar muy juntos. Una posible solución es tener un rand ponderado, pero eso está más allá de mí.

+0

THanks mate :) Acabo de hacer algunos ajustes menores y funciona como un encanto :) –

+0

Creo que sabes que esto no genera una serie completamente aleatoria, de lo contrario no habría necesidad de barajar al final;) ​​ Seguramente hay mucha aleatoriedad allí, pero la creación de rands en reacción a rands y totales previos puede introducir tendencias -libros en la distribución- que pueden manifestarse en ciertas pruebas y aplicaciones. – strainer

+0

@strainer Como mencioné en "EDIT" cuando el valor de $ n se hace grande, los valores parecen agruparse cerca del final. Esto probablemente podría ser resuelto por un rand ponderado. Este es un problema muy difícil de resolver sin el problema de aglomeración. –

0

no estoy seguro de si he entendido bien, pero trata de esto:

$n = 4; 
$max = 30; 
$array = array(); 

do { 
    $random = mt_rand(0, $max); 

    if (!in_array($random, $array)) { 
     $array[] = $random; 
     $n--; 
    } 
} while (n > 0); 
+0

Necesito cuatro números que agreguen a la variable $ max que ha utilizado. Como el ejemplo que he usado arriba: array (5, 7, 10, 8) // estos suman hasta 30 Disculpa por no ser clara. –

+1

Esto no garantiza que los números realmente sumen 30. Puede hacer que el último número no sea aleatorio, por lo que se suma a la cantidad correcta ... después de todo, no todos pueden ser aleatorios. Sin embargo, si ese número ya está en la matriz, tiene un pequeño problema :) – Thorarin

-2

Hope esto le ayudará más ....

approch-1

$aRandomarray = array(); 
for($i=0;$i<100;$i++) 
{ 
    $iRandomValue = mt_rand(1000, 999); 
    if (!in_array($iRandomValue , $aRandomarray)) { 
     $aRandomarray[$i] = $iRandomValue; 
    } 
} 

Approch-2

$aRandomarray = array(); 
for($i=0;$i<100;$i++) 
{ 
    $iRandomValue = mt_rand(100, 999); 
    $sRandom .= $iRandomValue; 
} 
array_push($aRandomarray, $sRandom); 
+0

No estoy muy seguro de cómo se crea n cantidad de números para sumar una cantidad específica? –

0

haberme perdido -así necesitan '' no hay duplicados demasiado
para virar en un 'Deduplicator' ... lo puse en el otro question

Para generar una serie de números aleatorios con una suma fija:

  • hacer una serie de números aleatorios (de mayor magnitud práctica para ocultar la granularidad ...)
  • calcular su suma
  • multiplican cada uno en serie por desiredsum/suma

(básicamente, a la escala de una serie aleatoria a su nuevo tamaño)

Luego es el redondeo de error para ajustar por:

  • suma y su diferencia a calcular de de suma deseada
  • añadir el sumdiff a una elemento aleatorio en serie si no da como resultado un negativo, si hace un bucle a otro elemento aleatorio hasta que quede bien.
  • que se ultratight lugar añadir o reste 1 bit a elementos aleatorios hasta sumdiff = 0

Algunos no aleatoriedad resultante de hacerlo así es que si la magnitud de los randoms fuente es demasiado pequeño causando granularidad en el resultado.

no tengo php, pero aquí hay un tiro -

$n = ;    //size of array 
$targsum = ;  //target sum 
$ceiling = 0x3fff; //biggish number for rands 
$sizedrands = array(); 

$firstsum=0; 
$finsum=0; 

//make rands, sum size 
for($count=$n; $count>0; $count--) 
{ $arand=rand(0, $ceiling); 
    $sizedrands($count)=$arand; 
    $firstsum+=$arand; } 

//resize, sum resize 
for($count=$n; $count>0; $count--) 
{ $sizedrands($count)=($sizedrands($count)*$targsum)/$firstsum; 
    $finsum+=$sizedrands($count); 
    } 

//redistribute parts of rounding error randomly until done 
$roundup=$targsum-$finsum; 

$rounder=1; if($roundup<0){ $rounder=-1; } 

while($roundup!=0) 
{ $arand=rand(0, $n); 
    if(($rounder+$sizedrands($arand)) > 0) 
    { $sizedrands($arand)+=$rounder; 
    $roundup-=$rounder; } 
    } 
Cuestiones relacionadas