Is there an efficient way to generate N random integers in a range that have a given sum or average?

前端 未结 5 1206
感动是毒
感动是毒 2020-11-27 19:15

Is there an efficient way to generate a random combination of N integers such that—

  • each integer is in the interval [min, max],
5条回答
  •  渐次进展
    2020-11-27 19:37

    Here is the algorithm from John McClane's PermutationPartitionGenerator, in another answer on this page. It has two phases, namely a setup phase and a sampling phase, and generates n random numbers in [min, max] with the sum sum, where the numbers are listed in random order.

    Setup phase: First, a solution table is built using the following formulas (t(y, x) where y is in [0, n] and x is in [0, sum - n * min]):

    • t(0, j) = 1 if j == 0; 0 otherwise
    • t(i, j) = t(i-1, j) + t(i-1, j-1) + ... + t(i-1, j-(max-min))

    Here, t(y, x) stores the relative probability that the sum of y numbers (in the appropriate range) will equal x. This probability is relative to all t(y, x) with the same y.

    Sampling phase: Here we generate a sample of n numbers. Set s to sum - n * min, then for each position i, starting with n - 1 and working backwards to 0:

    • Set v to a random integer in [0, t(i+1, s)).
    • Set r to min.
    • Subtract t(i, s) from v.
    • While v remains 0 or greater, subtract t(i, s-1) from v, add 1 to r, and subtract 1 from s.
    • The number at position i in the sample is set to r.

    EDIT:

    It appears that with trivial changes to the algorithm above, it's possible to have each random number use a separate range rather than use the same range for all of them:

    Each random number at positions i ∈ [0, n) has a minimum value min(i) and a maximum value max(i).

    Let adjsum = sum - Σmin(i).

    Setup phase: First, a solution table is built using the following formulas (t(y, x) where y is in [0, n] and x is in [0, adjsum]):

    • t(0, j) = 1 if j == 0; 0 otherwise
    • t(i, j) = t(i-1, j) + t(i-1, j-1) + ... + t(i-1, j-(max(i-1)-min(i-1)))

    The sampling phase is then exactly the same as before, except we set s to adjsum (rather than sum - n * min) and set r to min(i) (rather than min).


    EDIT:

    For John McClane's CombinationPartitionGenerator, the setup and sampling phases are as follows.

    Setup phase: First, a solution table is built using the following formulas (t(z, y, x) where z is in [0, n], y is in [0, max - min], and x is in [0, sum - n * min]):

    • t(0, j, k) = 1 if k == 0; 0 otherwise
    • t(i, 0, k) = t(i - 1, 0, k)
    • t(i, j, k) = t(i, j-1, k) + t(i - 1, j, k - j)

    Sampling phase: Here we generate a sample of n numbers. Set s to sum - n * min and mrange to max - min, then for each position i, starting with n - 1 and working backwards to 0:

    • Set v to a random integer in [0, t(i+1, mrange, s)).
    • Set mrange to min(mrange, s)
    • Subtract mrange from s.
    • Set r to min + mrange.
    • Subtract t(i, mrange, s) from v.
    • While v remains 0 or greater, add 1 to s, subtract 1 from r and 1 from mrange, then subtract t(i, mrange, s) from v.
    • The number at position i in the sample is set to r.

提交回复
热议问题