Algorithm 生成总和为n的随机数

Algorithm 生成总和为n的随机数,algorithm,random,Algorithm,Random,如何生成1到n个随机数(大于0的正整数),其总和正好为n n=10时的示例结果: 10 2,5,3 1,1,1,1,1,1,1,1,1,1 1,1,5,1,1,1 每个排列都应该有相同的发生概率,但是,我不需要它在数学上精确。如果由于模误差,概率不一样,我不在乎 是否有一个用于此的go-to算法?我只发现数值的数量是固定的算法(即,给我m个随机数,加起来等于n)。使用模 这将使你的一天: #include <stdio.h> #include <stdlib.h> #i

如何生成1到n个随机数(大于0的正整数),其总和正好为n

n=10时的示例结果:

10
2,5,3
1,1,1,1,1,1,1,1,1,1
1,1,5,1,1,1
每个排列都应该有相同的发生概率,但是,我不需要它在数学上精确。如果由于模误差,概率不一样,我不在乎

是否有一个用于此的go-to算法?我只发现数值的数量是固定的算法(即,给我m个随机数,加起来等于n)。

使用模

这将使你的一天:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    srand(time(0));
    int n=10;
    int x=0; /* sum of previous random number */
    while (x<n) {
                int r = rand() % (n-x) + 1;
                printf("%d ", r);
                x += r;
    }
    /* done */
    printf("\n");
}

将数字n想象成一条由n个相等的、不可分割的部分组成的线。您的数字是这些部分的长度,这些部分的总和为整体。可以在任意两个截面之间剪切原始长度,也可以不剪切

这意味着存在n-1潜在切点

选择一个随机的n-1-位数字,即介于02^(n-1)之间的数字;它的二进制表示形式告诉您在哪里剪切

0 : 000 : [-|-|-|-] : 1,1,1,1
1 : 001 : [-|-|- -] :  1,1,2
3 : 011 : [-|- - -] :   1,3
5 : 101 : [- -|- -] :   2,2
7 : 111 : [- - - -] :    4
等等


python-3中的实现

import random


def perm(n, np):
    p = []
    d = 1
    for i in range(n):
        if np % 2 == 0:
            p.append(d)
            d = 1
        else:
            d += 1
        np //= 2
    return p


def test(ex_n):
    for ex_p in range(2 ** (ex_n - 1)):
        p = perm(ex_n, ex_p)
        print(len(p), p)


def randperm(n):
    np = random.randint(0, 2 ** (n - 1))
    return perm(n, np)

print(randperm(10))
您可以通过为小型n

test(4)
输出:

4 [1, 1, 1, 1]
3 [2, 1, 1]
3 [1, 2, 1]
2 [3, 1]
3 [1, 1, 2]
2 [2, 2]
2 [1, 3]
1 [4]

@塞加约兹:我也想到了这个算法,但是,它看起来好像偏离了“每个排列的概率相同”,不是吗?很容易有10个以上的排列,但“10”的概率为1/10。(我知道,我说过它不必精确到数学上,但也不应该太离谱)只是为了澄清一下——你说的是“数字”,但你的例子都是整数。是否排除浮点解决方案?允许负值吗?零呢?我不确定为什么人们投票认为这个问题“太广泛”,我如何才能改进这个问题?请留言,谢谢!没有尝试,也没有标记来指明你写这篇文章的语言。对我来说,这看起来更像是一个问题,而不是一个编程问题。@TobySpeight:最后我想要C代码,但我忽略了C标记,因为我对算法感兴趣,而不是具体的实现。算法问题不是StackOverflow的一部分吗?至于尝试,如果我自己找不到方法,我就无权在这里发帖了?谢谢你的解释,这是一个非常好的答案。我们不需要一次生成决策树的所有n个比特——如果我们有一个随机比特源,我们可以根据需要获取它们。这可以避免我们不会用于算术的庞大算术数字的开销。我喜欢你解决问题的方式,也非常喜欢你演示示例的方式。这似乎偏向于较短的序列;示例输出中只有一个以
1
开头,但如果从所有可能性中公平选择,我们预计其中大约一半以
1
开头。
4 [1, 1, 1, 1]
3 [2, 1, 1]
3 [1, 2, 1]
2 [3, 1]
3 [1, 1, 2]
2 [2, 2]
2 [1, 3]
1 [4]