总和在给定范围内的随机数数组?

Array of random numbers with sum in given range?

在 C 中,如何获得 n 个数字的数组(在我的例子中每个数字为 0x00-0xFF),其总和在给定范围内 0..k?

almost 重复 C++ multiple random numbers adding up to equal a certain number 以特定总和为目标,但在我的情况下总和可以是 0..k.

之间的任何值

[0, 255] 范围内创建一个数字很容易。

如果k > 255*nk < 0无解,很容易判断

如果0 <= k <= 255*n,解决方案存在。这里只讲n > 1条件

您创建了n-1个随机数,n-1个数之和为s1,假设第n个数为x。所以s1 + x = k,x应该是[0, 255]如果n-1个数都在[0, a]范围内,那么(n-1)*a + 255 >= k,我们得到a >= (k-255)/(n-1).

如果k > 255,就让a = (k-255)/(n-1)。这意味着 s1[0, k-255]。那么第n个数x可以是[0, 255]内的任意随机数。 所以解决方案是任意 select n-1 个数字 [0, (k-255)/(n-1)] (你知道 (k-255)/(n-1) <= 255,因此它满足你的条件),并且 select 一个随机数在 [0, 255].

如果 k <= 255,任意 select n 个数字都在 [0, k/n] 内(你知道 k/n 在 [0, 255] 内)。

假设k小于255 * n,一种解决方案是将k / n分配给数组的每个元素,然后随机将数组元素减去一个值。

// for (int i = 0; i < n; i++) array[i] = k / n;
// for (int i = 0; i < n; i++) array[i] -= randbetween(0, array[i]);
for (int i = 0; i < n; i++) array[i] = randbetween(0, k / n);

这具有 k / 2 的预期总和。通过调整 randbetween() 函数,您可以更改结果数组总和的概率。

您需要指定所需的随机数分布。

如果没有进一步的要求,我会建议以下之一:


(1)

  • 在区间0 .. k
  • 中选择随机数a[1]
  • 在区间0 .. k-a[1]
  • 中选择随机数a[2]
  • 在区间0 .. k-a[1]-a[2][=59=中取随机数a[3] ]
  • ...
  • 在区间0 .. k-a[1]-a[2]-...-a[n-]中选择随机数a[n] 1]

如果随机数的范围有上限m,使用min(k-a[1]-... m)作为区间的上限。

缺点:你会得到很多小数,只有几个大数。


(2)

  • 在区间 0 中选择 n 个随机数 a[1], .., a[n]。 .m,m为上限
  • s = a[1]+a[2]+...+a[n]
  • 将每个 a[i] 乘以 k/s(如果需要整数,向下舍入)

缺点:这种方式不太可能得到大数字。如果需要整数,由于舍入误差,数字总和与 k 之间可能会有差距。


我想你会得到 "nicer" 个带有选项 (2) 的数字,但如上所述,这取决于要求。