Generate N random numbers within a range with a constant sum

前端 未结 5 856
暗喜
暗喜 2020-12-03 12:26

I want to generate N random numbers drawn from a specif distribution (e.g uniform random) between [a,b] which sum to a constant C. I have tried a couple of solutions I could

5条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-03 12:57

    For my answer I'll assume that we have a uniform distribution.

    Since we have a uniform distribution, every tuple of C has the same probability to occur. For example for a = 2, b = 2, C = 12, N = 5 we have 15 possible tuples. From them 10 start with 2, 4 start with 3 and 1 starts with 4. This gives the idea of selecting a random number from 1 to 15 in order to choose the first element. From 1 to 10 we select 2, from 11 to 14 we select 3 and for 15 we select 4. Then we continue recursively.

    #include 
    #include 
    
    std::default_random_engine generator(time(0));
    int a = 2, b = 4, n = 5, c = 12, numbers[5];
    
    // Calculate how many combinations of n numbers have sum c
    int calc_combinations(int n, int c) {
        if (n == 1) return (c >= a) && (c <= b);
        int sum = 0;
        for (int i = a; i <= b; i++) sum += calc_combinations(n - 1, c - i);
        return sum;
    }
    
    // Chooses a random array of n elements having sum c
    void choose(int n, int c, int *numbers) {
        if (n == 1) { numbers[0] = c; return; }
    
        int combinations = calc_combinations(n, c);
        std::uniform_int_distribution distribution(0, combinations - 1);
        int s = distribution(generator);
        int sum = 0;
        for (int i = a; i <= b; i++) {
            if ((sum += calc_combinations(n - 1, c - i)) > s) {
                numbers[0] = i;
                choose(n - 1, c - i, numbers + 1);
                return;
            }
        }
    }
    
    int main() { choose(n, c, numbers); }
    

    Possible outcome:

    2
    2
    3
    2
    3
    

    This algorithm won't scale well for large N because of overflows in the calculation of combinations (unless we use a big integer library), the time needed for this calculation and the need for arbitrarily large random numbers.

提交回复
热议问题