8

とにかく、合計が常に定数になる一連の乱数を生成する方法があるかどうかを考えています。たとえば、20 は 5 つの数字 (1、2、3、4、10) に分割できます。合計が 20 に等しい限り、5 つの数字のそれぞれが何であるかは気にしません。プログラムでそうする方法はありますか?

4

7 に答える 7

16

均一な分布を得るには、合計を数直線と考え、線分に対して乱数を生成するのではなく、線に沿った点として n-1 の数を生成し、減算して線分を取得するのがコツです。ojrandlibの関数は次のとおりです。

static int compare(const void *a, const void *b) {
    return *(int*)a - *(int*)b;
}
void ojr_array_with_sum(ojr_generator *g, int *a, int count, int sum) {
    int i;
    for (i = 0; i < count-1; ++i) { a[i] = ojr_rand(g, sum+1); }
    qsort(a, count-1, sizeof(int), compare);
    a[count-1] = sum;
    for (i = count-1; i > 0; --i) { a[i] -= a[i-1]; }
}

ojr_rand(g, limit)0 から limit-1 までの一様乱数整数を生成します。次に、この関数は、に加算されるランダムな整数で配列aを埋めます。これを他の RNG に適応させるのはそれほど難しいことではありません。countsum

于 2013-06-02T15:05:30.413 に答える
2

このメソッドはジョブを実行し、値間の「相違度」を制御することもできます (たとえば、配列値を互いに近づけたい場合)。

/**
     * Create array of positive integers which exactly sums to a given (integer) number.
     * @param {Number} number of items
     * @param {Number} sum  required sum
     * @param {Number} [d=100] difference degree between the values (0..100)
     */
    randomSumArray: function(len, sum, d) {
        var _sum = 0;
        var arr = [];
        var n, i;

        if (!d && d !== 0) {
            d = 100;
        }

        for (i = 0; i < len; i++) {
            var from = (100 - d) * 1000,
                to = (100 + d) * 1000,
                n = Math.floor(Math.random() * (to - from + 1) + from); //random integer between from..to

            _sum += n;
            arr.push(n);
        }

        var x = sum / _sum;

        _sum = 0; //count sum (again)
        for (var i = 0; i < len; i++) {
            arr[i] = Math.round(arr[i] * x);
            _sum += arr[i];
        }

        var diff = sum - _sum;

        // Correct the array if its sum does not match required sum (usually by a small bit)
        if (diff) {
            x = diff / Math.abs(diff); //x will be 1 or -1
            var j = 0;
            while (diff && j < 1000) { //limit to a finite number of 'corrections'
                i = Math.floor(Math.random() * (len + 1)); //random index in the array
                if (arr[i] + x >= 0) {
                    arr[i] += x;
                    diff -= x;
                }
                j++;
            }
        }

        return arr;
    }
于 2014-11-17T15:57:30.127 に答える
0

これはちょっとしたトリックですが、それでも :)
私はこれを可能なアイデアとして提示し
ます。

必要な乱数が必要な整数でない場合:
[0,1] の間で N 個の乱数を生成し、配列を S に正規化できます:)

for(i=0; i<N; i++)
   arr[i] = rand;

cursum = 0;
for(i=0; i<N; i++)
   cursum+=arr[i];

norm = S / cursum;

for(i=0; i<N; i++)
    arr[i] *= norm;
于 2013-07-09T07:58:37.777 に答える
-1

ライブラリ関数を使用して乱数を取得します。

ここで、必要な乱数は、生成された乱数 mod 許容合計です。

次に、生成した数だけ許容合計を減らします。

ライブラリの乱数ジェネレーターが返す最初の乱数が 109 だとします。

したがって、最初の乱数は 109 mod 20 = 9 です。許容合計を 20 -9 = 11 に更新します。

許可された合計がゼロになるまで続けます。

あなたが言及した5番は単なる例だと思います。乱数の数を正確に 5 にしたい場合は、このメソッドを変更する必要があるかもしれません。

于 2013-06-02T14:05:45.540 に答える
-2

はい!このアルゴリズムを試してください

num1=rand()%20;  
num2=rand()%(20-num1);  
num3=rand()%(20-num1-num2);  
num4=rand()%(20-num1-num2-num3);  
num5=20-num4-num3-num2-num1;  

したがって、5 つの数字はランダムであり、合計すると 20 になります
[必要に応じてループを使用してこれを行うことができます]

一般に、最初に数 [n] をランダムに生成し、合計すると手札の数 [K] になります。

 n=rand()%k;--assuming the number of rand numbers you want are between 1 and k[sum]
    n1=rand()%k;
    n2=rand()%(k-n1)
    .
    .
    nn-1=rand()%(k-n1...-nn-2)
    nn=k-n1-n2...nn-1

それがあなたを助けることを願っています!

于 2013-06-02T14:16:38.000 に答える