总和在给定范围内的随机数数组?
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*n
或k < 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) 的数字,但如上所述,这取决于要求。
在 C 中,如何获得 n 个数字的数组(在我的例子中每个数字为 0x00-0xFF),其总和在给定范围内 0..k
?
almost 重复 C++ multiple random numbers adding up to equal a certain number 以特定总和为目标,但在我的情况下总和可以是 0..k
.
在 [0, 255]
范围内创建一个数字很容易。
如果k > 255*n
或k < 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) 的数字,但如上所述,这取决于要求。