8

我在想是否无论如何都要生成一组随机数,其总和总是一个常数。例如,20 可以分为 5 个数字(1、2、3、4、10)我不在乎这 5 个数字中的每一个是什么,只要它们的总和等于 20。无论如何以编程方式这样做?

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然后,此函数用count添加到的随机整数填充数组sum。将其适应任何其他 RNG 应该不会太难。

于 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 回答
0

如果生成的数字不一定是正数或范围内。
你可以计算出最后一个数字可以是S - SUM(A1..A[N-1])

N-1 个随机数的选择显然是统一的,
因为最后一个数字无论如何都取决于其余的数字
(每个集合只有一个选项用于最后一个数字)。

均匀性不受阻碍。

Arr = new int[N];

int sum=0;
for(i=0; i<N-1; i++)
{
    int x = getRandomInt();
    sum += x;
    Arr[i] = x;
}
Arr[N-1] = S - sum;
return Arr;
于 2013-07-14T14:33:52.807 回答
-1

使用库函数获取随机数。

现在你想要的随机数是生成的随机数 mod 允许的总和。

接下来,您将允许的总和减去您刚刚生成的数字。

假设您的库随机数生成器返回的第一个随机数是 109。

所以你的第一个随机数是 109 mod 20 = 9。将你的允许总数更新为 20 -9 = 11。

您继续前进,直到您的允许总和为零。

请注意,我假设您提到的数字 5 只是一个示例。如果您希望随机数的数量恰好为 5,您可能必须修改此方法。

于 2013-06-02T14:05:45.540 回答
-1

在我的情况下,我必须对值数组执行此操作,这需要 Sum 并将其随机拆分为数字范围。

    <html>
<script type="text/javascript">
function f(){
var array = [{
    order: '1-2480831',
    value: 2040
}, {
    order: 'BAESYS-2012-0001',
    value: 570
}, {
    order: 'BAESYS-2012-0002',
    value: 773
}, {
    order: '1-3840231',
    value: 299
}, {
    order: '1-3840298',
    value: 1609
}, {
    order: '1-3841519',
    value: 1940
}];

    var splitInto = 3;

    document.write("[");
    for (i=0; i<array.length; i++)
    {
        document.write("{ Id : '"+array[i].order+"', Data : [");
    var result = RandGenerator(splitInto,array[i].value);
    var sum = 0;
            for(ii =0;ii<result.length; ii++){
                sum += result[ii];
            document.write(result[ii]+',');
            }
            document.write("]},");
    }
    document.write("]");
}

function RandGenerator(count, sum) {
    var a = [];
    for (iii = 0; iii < count-1; iii++) 
        { 
            a[iii] = getRandToValue(sum);
            sum -= a[iii];
        }
    a[count-1] = sum;
    return a;
}

function getRandToValue(maxRand)
{
    var random = Math.random();
    var computed = (maxRand)*random;
    return computed;
}

f();
</script>
</html>
于 2014-02-24T12:59:06.780 回答
-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;  

所以确定这五个数字是随机的,它们总和为 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 回答