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

前端 未结 5 1219
感动是毒
感动是毒 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:43

    I have not tested this, so it is not really an answer, just something to try which is too long to fit into a comment. Start with an array which meets the first two criteria and play with it so it still meets the first two, but is a lot more random.

    If the mean is an integer, then your initial array can be [4, 4, 4, ... 4] or maybe [3, 4, 5, 3, 4, 5, ... 5, 8, 0] or something simple like that. For a mean of 4.5, try [4, 5, 4, 5, ... 4, 5].

    Next pick a pair of numbers, num1 and num2, in the array. Probably the first number should be taken in order, as with the Fisher-Yates shuffle, the second number should be picked at random. Taking the first number in order ensures that every number is picked at least once.

    Now calculate max-num1 and num2-min. Those are the distances from the two numbers to the max and min boundaries. Set limit to the smaller of the two distances. That is the maximum change allowed which will not put one or other of the numbers outside the allowed limits. If limit is zero then skip this pair.

    Pick a random integer in the range [1, limit]: call it change. I omit 0 from the pickable range as it has no effect. Testing may show that you get better randomness by including it; I'm not sure.

    Now set num1 <- num1 + change and num2 <- num2 - change. That will not affect the mean value and all elements of the array are still within the required boundaries.

    You will need to run through the whole array at least once. Testing should show if you need to run through it more than once to get something sufficiently random.

    ETA: include pseudocode

    // Set up the array.
    resultAry <- new array size N
    for (i <- 0 to N-1)
      // More complex initial setup schemes are possible here.
      resultAry[i] <- mean
    rof
    
    // Munge the array entries.
    for (ix1 <- 0 to N-1)  // ix1 steps through the array in order.
    
      // Pick second entry different from first.
      repeat
        ix2 <- random(0, N-1)
      until (ix2 != ix1)
    
      // Calculate size of allowed change.
      hiLimit <- max - resultAry[ix1]
      loLimit <- resultAry[ix2] - min
      limit <- minimum(hiLimit, loLimit)
      if (limit == 0)
        // No change possible so skip.
        continue loop with next ix1
      fi
    
      // Change the two entries keeping same mean.
      change <- random(1, limit)  // Or (0, limit) possibly.
      resultAry[ix1] <- resultAry[ix1] + change
      resultAry[ix2] <- resultAry[ix2] - change
    
    rof
    
    // Check array has been sufficiently munged.
    if (resultAry not random enough)
      munge the array again
    fi
    

提交回复
热议问题