2010-05-08 8 views
15

Sono abbastanza nuovo per PHP - programmazione in generale. Quindi, in pratica quello che ho bisogno di realizzare è, creare un array di x quantità di numeri (creato in modo casuale) il cui valore aggiungere fino a n:Creare numeri all'interno di un array che aggiungere fino a un certo lasso

Diciamo, devo creare 4 numeri che aggiungono fino a 30 Ho solo bisogno del primo set di dati casuali. I 4 e 30 qui sono variabili che verranno impostate dall'utente.

In sostanza qualcosa come

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 

Inoltre, non duplicati sono ammessi e tutti i numeri devono essere numeri interi positivi.

Ho bisogno valori all'interno di un array. Sono stato in giro a volte, tuttavia, la mia conoscenza è abbastanza limitata. Qualsiasi aiuto sarà molto apprezzato.

+0

sono duplicati ammessi? – Gumbo

+0

No. Mi dispiace, modificherò il mio post. –

+3

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

risposta

7

F prima di tutto, questo è un problema davvero interessante. Sono quasi sicuro che il mio approccio non distribuisca perfettamente i numeri, ma dovrebbe essere migliore di alcuni degli altri approcci qui.

Ho deciso di costruire l'array dal numero più basso verso l'alto (e mischiarli alla fine). Questo mi consente di scegliere sempre un intervallo casuale che consenta di ottenere risultati validi. Poiché i numeri devono essere sempre in aumento, ho risolto per il maggior numero possibile che assicura che una soluzione valida esiste ancora (cioè, se n = 4 e max = 31, se il primo numero è stato scelto per essere 7, allora non sarebbe essere possibile selezionare numeri maggiori di 7 tali che la somma di 4 numeri sia uguale 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: per grandi valori di $n vi ritroverete con un sacco di valori raggruppati verso la fine dell'array, poiché non v'è una buona probabilità si otterrà un valore casuale vicino al valore massimo costringendo il riposare per essere molto vicini. Una possibile soluzione è avere un rand ponderato, ma questo è oltre me.

+0

Compagno di compagni :) Ho appena apportato alcune modifiche minori e funziona come un fascino :) –

+0

Penso che tu sappia che questo non genera una serie completamente casuale, altrimenti non ci sarebbe bisogno di rimescolare alla fine;) C'è sicuramente un sacco di casualità, ma creare rands in risposta a precedenti rand e totali può introdurre tendenze - grumi nella distribuzione - che possono manifestarsi in alcuni test e applicazioni. – strainer

+0

@strainer Come menzionato nel "MODIFICA" quando il valore $ n diventa grande, i valori sembrano aggregarsi verso la fine. Questo potrebbe probabilmente essere risolto da un rand ponderato. Questo è un problema molto complicato da risolvere senza il problema dei grumi. –

0

non sono sicuro se ho capito bene, ma provare questo:

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

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

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

Ho bisogno di quattro numeri che si aggiungono alla variabile $ max che hai usato. Come nell'esempio che ho usato sopra: array (5, 7, 10, 8) // questi si sommano al 30 Ci scusiamo per essere un compagno poco chiaro. –

+1

Questo non garantisce che i numeri in realtà aggiungano fino a 30. Potresti rendere l'ultimo numero non casuale in modo che sommati alla giusta quantità .. dopo tutto, non possono essere tutti casuali. Se questo numero è già presente nell'array, si ha un piccolo problema :) – Thorarin

-2

Spero che questo vi aiuterà di più ....

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

Non sono abbastanza sicuro di come questo crea n quantità di numeri da aggiungere a un importo specifico? –

0

dispiace di aver perso 'duplicati' troppo
-così bisogno di virare su un 'DeDuplicator' ... ho messo in un altro question

Per generare una serie di numeri casuali con una somma fissa:

  • creare una serie di numeri casuali (di grandezza maggiore per nascondere la granularità ...)
  • calcolare la loro somma
  • moltiplicare ciascuna in serie desiredsum/somma

(basicaly per ridimensionare una serie casuale alla sua nuova dimensione)

Poi v'è errore di arrotondamento per regolare:

  • somma ricalcolo e la sua differenza dalla somma desiderata
  • aggiungere il sumdiff ad un elemento casuale in serie se non risulta in un negativo , se si esegue il ciclo su un altro elemento casuale fino a fine.
  • da ultratight invece aggiungere o sottrarre 1 bit di elementi casuali fino sumdiff = 0

Alcuni non casualità derivante dal farlo in questo modo è che se la grandezza delle randoms di origine è troppo piccola causando granularità nel risultato.

Non ho php, ma qui è un colpo -

$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; } 
    } 
Problemi correlati