推荐学习书目
› Learn Python the Hard Way
Python Sites
› PyPI - Python Package Index
› http://diveintopython.org/toc/index.html
› Pocoo
值得关注的项目
› PyPy
› Celery
› Jinja2
› Read the Docs
› gevent
› pyenv
› virtualenv
› Stackless Python
› Beautiful Soup
› 结巴中文分词
› Green Unicorn
› Sentry
› Shovel
› Pyflakes
› pytest
Python 编程
› pep8 Checker
Styles
› PEP 8
› Google Python Style Guide
› Code Style from The Hitchhiker's Guide
commoccoom
V2EX  ›  Python

请教一个问题,生成 10 个随机数 [0,100] 且最终 10 个随机数之和为 100 , 用 Python 如何实现

  •  1
     
  •   commoccoom · Jan 20, 2019 · 28262 views
    This topic created in 2851 days ago, the information mentioned may be changed or developed.
    Supplement 1  ·  Jan 21, 2019
    感谢大家的帮助,看了大家的回复后感觉确实有点像微信红包的算法,但是红包是不包含 0 的。另外,我也感觉标题中的“随机”这个表述有问题,应该是 [从 [0,100] 取 10 个数,使之和等于 100,可取 0 和 100 ] 不知道这次表述是否合适了。
    Supplement 2  ·  Jan 21, 2019
    数字可重复
    Supplement 3  ·  Jan 21, 2019
    感谢各位的帮助,我会试试各位给出的方法的。
    167 replies  •  2019-03-08 21:50:24 +08:00
    1  2  
    ❮ ❯
    eijuziew
    eijuziew
    Jan 20, 2019
    1
    mark 我也想知道
    alvin666
    alvin666
    Jan 20, 2019 via Android❤️1
    2
    这就不叫随机数吧...

    而且最简单的方法就是随机生成,然后总和 /100 = k,每个数再 /k
    celeron533
    celeron533
    Jan 20, 2019❤️139
    3
    在一根 1 到 100 的数轴上,随机取 9 个点,拿到 10 个线段。计算每个线段的长度,即是取值。
    weijidong
    weijidong
    Jan 20, 2019 via iPhone
    4
    关注
    weijidong
    weijidong
    Jan 20, 2019 via iPhone
    5
    @celeron533 牛逼
    JCZ2MkKb5S8ZX9pq
    JCZ2MkKb5S8ZX9pq
    Jan 20, 2019
    6
    需要补全一下问题,比如你现在包含 0,是否确定?另外 10 个随机数可以重复吗?
    如果不可以重复,那第一步取值范围就剩 1-55 或者 0-64 了。
    Kagari
    Kagari
    Jan 20, 2019
    7
    @celeron533 #3 稳了,反正没要求是整数
    JCZ2MkKb5S8ZX9pq
    JCZ2MkKb5S8ZX9pq
    Jan 20, 2019❤️1
    8
    有个思路是先在一个范围里随机取 10 个数,然后 sum,然后缩放到 100,然后做点去重的偏移。
    commoccoom
    commoccoom
    OP
    Jan 20, 2019
    9
    @JCZ2MkKb5S8ZX9pq 包含 0 和 100,可以重复,需要是整数 @Kagari
    chinvo
    chinvo
    Jan 20, 2019 via iPhone❤️1
    10
    在马桶上随便写写,没怎么仔细想,各位见笑

    伪代码

    func(nums: array = [0])
    if i=nums.length < 11
    nums[i] = rand(nums[i-1], 100)
    return func(nums)
    nums.removeAt(0)
    return nums

    func()

    但是严格意义上讲,虽然数列中的每个元素都是随机函数生成的,但是这个数列并不是随机数列
    chinvo
    chinvo
    Jan 20, 2019 via iPhone
    11
    @JCZ2MkKb5S8ZX9pq #6 不含 0 是 (0, 100]
    F1024
    F1024
    Jan 20, 2019
    12
    递减呗
    emric
    emric
    Jan 20, 2019❤️1
    13
    fisher yates 洗牌算法,生成 1~100 数组打乱即可。
    alvin666
    alvin666
    Jan 20, 2019 via Android
    14
    @celeron533 这根本不是随机数
    JCZ2MkKb5S8ZX9pq
    JCZ2MkKb5S8ZX9pq
    Jan 20, 2019❤️3
    15
    照着 @celeron533 思路
    points = [random.randint(0, 100) for i in range(9)] # 生成 9 个随机点
    points = [0] + sorted(points) + [100] # 排个队
    points = [points[i + 1] - points[i] for i in range(10)] # 算每段距离
    print(points, sum(points))
    emric
    emric
    Jan 20, 2019
    16
    忽略我上面的答案,没认真审题...
    smdbh
    smdbh
    Jan 20, 2019
    17
    那就生成 9 个随机数,范围看你需求
    最后一个 100 - 9 个和 不就好了。
    chinvo
    chinvo
    Jan 20, 2019 via iPhone
    18
    @smdbh #17 你这样分布可能不够分散
    zys864
    zys864
    Jan 20, 2019 via Android
    19
    生成 9 个随机数,然后用 100 减去 9 个数的和作为第十个数
    niuoh
    niuoh
    Jan 20, 2019 via Android
    20
    第一次取 0 到 100 第二次取 0 到 100 减第一个数
    lance6716
    lance6716
    Jan 20, 2019 via Android❤️2
    21
    凡是描述概率问题的时候不给分布瞎答就可以了
    ps1aniuge
    ps1aniuge
    Jan 20, 2019
    22
    $数组 = 1..100
    while ($true)
    {
    $a,$b,$c,$d,$e,$f,$g,$h,$i,$j = Get-Random -InputObject $数组 -Count 10
    $和 = $a + $b + $c + $d + $e + $f + $g + $h + $i + $j
    if ($和 -lt 120)
    {
    Write-Host "$a $b $c $d $e $f $g $h $i $j $k"
    }
    }

    上面的 powershell 代码,设定值小于 120 时 ,5 分钟没出结果。
    我估计 -eq 100 得一年才能出结果。而设定 -lt 200 很好出结果,大家可以试试。
    evgm
    evgm
    Jan 20, 2019
    23
    生成一个[0, 100] 的随机数,第二个数范围是 [0, 100-num1],第三个是[0, 100-num1-num2],以此类推?
    epicnoob
    epicnoob
    Jan 20, 2019
    24
    你这个不能叫随机数,近似使用可以 10+randint(-10,10)
    Vegetable
    Vegetable
    Jan 20, 2019 via iPhone
    25
    很有意思的问题,有很多实现方式,随着限制条件(去重,整数,负数)的增加,变数更多,很适合作为面试口答题哦。
    stevenbipt
    stevenbipt
    Jan 20, 2019 via Android
    26
    生成 9 个,最后一个用 100 减去🌚🌚🌚
    18219304774
    18219304774
    Jan 20, 2019
    27
    Python 没学过,用 js 实现一个

    var arr=new Array(10);
    for(let i=0; i<10; i++){
    arr[i]=0;
    }
    for(let i=0; i<100; i++){
    var index=Math.floor(Math.random()*10);
    arr[index]++
    }
    flowfire
    flowfire
    Jan 20, 2019 via Android
    28
    3 楼正解,取 9 个点然后拿到十个线段长度即可,如果需要整数,可以规定随机到的九个点都是整数即可
    ticotico
    ticotico
    Jan 20, 2019
    29
    random 取整数,加和,映射到 100 内( 100/加和总数*十个数总值)
    结果:前九个数+0.5 取整
    最后一个数 100-前九个数的合

    这个问题就是微信红包是怎么随机分配的吧
    iixy
    iixy
    Jan 21, 2019❤️1
    30
    10 个数和为 100,均值也就是 10,也就是说最好在 0-20 里面取值。
    而且绝对不能取到大于 91 的数,92-100 已经被排除在外了
    这种条件,还能叫随机吗
    yufz
    yufz
    Jan 21, 2019
    31
    https://gist.github.com/fei-ke/2e86bce8aa52bff5d0bf

    好多年前写过一个微信红包的算法( Java 的),可以拿去参考一下
    luozic
    luozic
    Jan 21, 2019 via iPhone
    32
    直接 100 落概率桶,总和为 10,难道还有负数?
    dapang1221
    dapang1221
    Jan 21, 2019❤️2
    33
    关键在于随机数不一定要同时生成吧
    第一个数 n[0] = rand(0, 100);
    第二个数 n[1] = rand(0, 100 - n[0]);
    第三个数 n[2] = rand(0, 100 - n[0] - n[1]);
    而且应该也是均匀分布的吧
    AX5N
    AX5N
    Jan 21, 2019
    34
    @gransh 可以取大于 91 的数。
    AX5N
    AX5N
    Jan 21, 2019
    35
    还是 3 楼的答案最好
    xujunfu
    xujunfu
    Jan 21, 2019 via Android
    36
    感觉三楼解法,稍微有 bug,就是有可能 9 个数全部落在 1 点(9 个点中有重复数出现);个人觉得这是个线性代数问题,先求解线性方程 组 x1+x2+…… x10=100 的所以解,然后从解的集合随机取出。
    CEBBCAT
    CEBBCAT
    Jan 21, 2019 via Android
    37
    这不就是微信红包算法吗?
    Linxing
    Linxing
    Jan 21, 2019❤️1
    38
    随机十次 每次范围都是 100 减去余下的数
    Linxing
    Linxing
    Jan 21, 2019
    39
    额 说错了 随机九次
    ywcjxf1515
    ywcjxf1515
    Jan 21, 2019 via iPad
    40
    就没人想到深度优先搜索嘛,深度优先能用其他图算法就可能能用。
    abysmalIQ
    abysmalIQ
    Jan 21, 2019
    41
    你要先定义你这里的“随机”是什么意思
    umbrellakkk
    umbrellakkk
    Jan 21, 2019❤️2
    42
    0-100 随机生成 10 个数,然后加起来,如果等于 100,直接输出,不等于就返回继续生成 10 个随机数,直到等于 100 为止,反正现在计算机快,不在乎没效率。
    imzhong
    imzhong
    Jan 21, 2019
    43
    你这是线性方程组求解
    yuikns
    yuikns
    Jan 21, 2019 via iPad
    44
    先随机十个数字,再求和,得到的结果除以 100 得到 f,对每个数字除以这个值即可。

    若需要,还可以高斯分布再 curve 一下
    imzhong
    imzhong
    Jan 21, 2019 via iPad
    45
    @yuikns 也可以随机出来 10 个,最后再加一个数使 11 个数总和为 100,然后随机出来的每一个数加上 1/10 最后一个数
    imzhong
    imzhong
    Jan 21, 2019
    46
    @imzhong 好吧,有负数...
    jssyxzy
    jssyxzy
    Jan 21, 2019
    47
    很简单的问题,你生成 9 个随机数不就是了,最后一个 100- 下。
    别杠说你这不是 10 个随机数,你题目本来就做不到 10 个数全部完全随机。
    jssyxzy
    jssyxzy
    Jan 21, 2019
    48
    @celeron533 感谢仁兄的思路。
    Mutoo
    Mutoo
    Jan 21, 2019
    49
    ayyll
    ayyll
    Jan 21, 2019 via Android
    50
    @umbrellakkk 计算机是快。。。但这不是写垃圾代码的理由
    Cbdy
    Cbdy
    Jan 21, 2019 via Android
    51
    概率论了解一下,47 楼正解
    bugcoder
    bugcoder
    Jan 21, 2019
    52
    整数:
    穷举所有相加等于 100 的 10 个[0, 100)整数的组合,然后每次随机抽取一组。
    非整数:
    每次随机完从剩下的份额里面随机就行了。
    opengps
    opengps
    Jan 21, 2019
    53
    这个做法,完全就是微信或支付宝的**随机红包**逻辑。参考 3 楼的方案使用几何角度解决很完美!!
    不过实现起来未必容易,要求普通程序员写数学模型算法不见得容易。那么可以先围绕单个平均值随机时候检查大小,每 2 个红包随机结果求和等于 2 个红包总平均值。
    xujinkai
    xujinkai
    Jan 21, 2019 via Android
    54
    楼主啊 看你拿来干嘛了 是要做红包还是只要求随机 红包的话还会多几个约束条件 比如取到小数点后两位 而且虽然随机但差距又不要太大
    airfling
    airfling
    Jan 21, 2019
    55
    你这是个伪命题,即使前面九个数据都满足,最后一个数据就不可能是随机数,你这个最终结果是越来越不随机
    lrh3321
    lrh3321
    Jan 21, 2019
    56
    先生成 10 个随机数 wi,作为权重。然后每个数是 100 * wi / sum(wi)
    Forbidden
    Forbidden
    Jan 21, 2019
    57
    @imzhong 这个思路也是可以的,10 个数之和大于 100 的,第 11 个数取负数即可,但要保证前 10 个数中最小一个要大于第 11 个数绝对值的 1/10
    或者最小的不参与减值,其他的减 1/9,然后又回到刚才的要避免的情况里面了……
    又或者是第 11 个数随机分 10 份,哈哈又变成原题了……
    NotFamous
    NotFamous
    Jan 21, 2019
    58
    感觉顶多只能随机前 9 个,第 10 个妥妥的 100 减去前边的和。。。(其实每次抽,下一个数都是 100 减去前边数的总和吧)
    MrUser
    MrUser
    Jan 21, 2019
    59
    坐等比 3# 更牛 B 的方法
    auciou2
    auciou2
    Jan 21, 2019❤️1
    60
    先获得所有的情形:0 ~ 100,共有 101 个数。
    假设要求这 10 个数不重复,这 10 个随机数共有:1+2+3+4+5+6+7+8+9+10+11=66 种。(其实不需要统计有多少种)

    编写一个循环程序,从 0-100,列举出所有的 10 个不重复的数的组合、与和,循环次数为 101*101。
    从这些组合中,让程序自动筛选出所有的和为 100 的(10 个数的)组合。

    之后,从这 10 个组合,随机拿出一个组合。
    再将这个拿到的组合,再进行随机排列大小。

    如果要生成 10 个随机数的和为 200、300,或者 N 个随机数的和为 M,同理。
    werty
    werty
    Jan 21, 2019
    61
    网上有微信红包算法, 抄一遍就行了,
    alex1504
    alex1504
    Jan 21, 2019
    62
    @celeron533 思路不错
    bigbigfly
    bigbigfly
    Jan 21, 2019
    63
    组合数学里的整数拆分了解下,思路:先有一个 1 行 100 列的数组,每个值为 1 ;再随机生成 100 内的 9 个数(升序排列),这样,每个间隔(如 0-随机生成的 9 个数中最小的那个,依次类推会一般有十个间隔)累加起来当做一个值,个人感觉这样很合理,很随机。
    jrient
    jrient
    Jan 21, 2019
    64
    其实题主的问题有两个分支:
    1. 直接获得 10 个数字
    2. 每次生成一个,一共生成 10 个数字
    hanwujibaby
    hanwujibaby
    Jan 21, 2019
    65
    @celeron533 学习了。这是数学思维啊。
    SeaRecluse
    SeaRecluse
    Jan 21, 2019
    66
    import random
    num_list = []
    tmp_num = 0
    tmp_sum = 0
    get_num = 0

    for i in range(1,10):
    tmp_sum = i * 10 - get_num
    tmp_num = random.randint(1,tmp_sum)
    get_num += tmp_num
    num_list.append(tmp_num)

    num_list.append(100 - get_num)
    print(num_list)
    PALELESS
    PALELESS
    Jan 21, 2019
    67
    先定义一个生成两个数的过程, 并给出总和
    第一个数为随机
    第二个数为和减去第一个数
    返回这两个数

    那么 10 个数即为:
    PALELESS
    PALELESS
    Jan 21, 2019
    68
    先定义一个生成两个数的过程, 参数为其和
    第一个数为随机
    第二个数为和减去第一个数
    返回这两个数

    那么 10 个数即为: 求出第一个随机数, 第二个数为第一个数减去第一个数, 用第二个数作为和接着递归

    不给代码了(空格按错多回了一次)
    lithiumii
    lithiumii
    Jan 21, 2019
    69
    比较看脸的算法,供参考(滑稽

    from random import randint
    sum_ints = 0
    while sum_ints != 100:
    ints = [randint(0,100) for ii in range(0,10)]
    sum_ints = sum(ints)
    print(ints)
    fromxt
    fromxt
    Jan 21, 2019
    70
    如果是要均匀分布随机数的话,可以采用 numpy 库里面的狄利克雷分布函数 numpy.random.dirichlet,这个函数能保证随机数是正的,和为 1.
    参考 https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.random.dirichlet.html

    import numpy as np
    np.random.dirichlet(np.ones(10))*100
    nicking
    nicking
    Jan 21, 2019
    71
    @jssyxzy 那万一那九个数相加已经大于 100 了呢
    xxlong
    xxlong
    Jan 21, 2019
    72
    @JCZ2MkKb5S8ZX9pq 算法有问题 出现了 0 的时候
    我觉得算法还是生成随机数后,用可控总和去减比较稳妥,因为不可能做到完全随机,如果第一个或者有一个随机数是 99 怎么办?我觉得这样比较稳妥:先生成 0~( 100-10 )的随机数 a,然后再生成 0~( a-10 )的随机数,最后一个用综合减去,这样能保证稳妥的随机性
    SunnyFeng
    SunnyFeng
    Jan 21, 2019
    73
    @jssyxzy 如果第 10 个数用 100 -的话,那有可能这个数是负数吧?
    SeaRecluse
    SeaRecluse
    Jan 21, 2019
    74
    @SeaRecluse 写错了,是 i*11
    xinClever
    xinClever
    Jan 21, 2019
    75
    num1 = [0, 100],num2 = [0, 100 - num1],num3 = [0, 100 - num1 - num2],以此类推,可以吧?
    celeron533
    celeron533
    Jan 21, 2019
    76
    @commoccoom 但实际上最可操作的还是取一堆介于 0-1 之间的浮点 /单精 /双精,然后把它们相加,最后总和与 100 等比放大。这个之前#2 @alvin666 操作过了
    beforeuwait
    beforeuwait
    Jan 21, 2019
    77
    3 楼正解
    huahuajun9527
    huahuajun9527
    Jan 21, 2019
    78
    照 3 楼说的

    import random


    a = [random.randint(0, 100) for i in range(10)]
    a.append(0)
    a.append(100)
    a.sort()

    b = [a[i + 1] - a[i] for i in range(10 + 1)]

    print(b)
    print(sum(b))
    huahuajun9527
    huahuajun9527
    Jan 21, 2019
    79
    @huahuajun9527 数字取多了,写成取 11 个数了==
    dlrdegk
    dlrdegk
    Jan 21, 2019
    80
    @celeron533 #3 看到这个第一反应:《几何原本》
    commoccoom
    commoccoom
    OP
    Jan 21, 2019
    81
    @xinClever 我能想到的也是这样。
    commoccoom
    commoccoom
    OP
    Jan 21, 2019
    82
    @celeron533 感谢帮助!
    shintendo
    shintendo
    Jan 21, 2019
    83
    我这个思路不知道对不对:
    想象你有 100 个小球排成一行,标号 1-100,现在要随机插入 9 块隔板,把它分成 10 段,每段的个数就是你要的结果。
    再把隔板视为特殊的小球,问题转化为从 109 个小球中随机选 9 个。
    SeaRecluse
    SeaRecluse
    Jan 21, 2019
    84
    @huahuajun9527 这样的写法其实对于第一位和最后一位是不公平的
    shintendo
    shintendo
    Jan 21, 2019
    85
    看错了,是 0-100。
    那就是从 0-109 中随机取 9 个整数即可。
    SeaRecluse
    SeaRecluse
    Jan 21, 2019❤️1
    86
    @shintendo 你的想法是对的,但是是插入 10 个隔板,因为围成圈后没有开头结尾。
    SeaRecluse
    SeaRecluse
    Jan 21, 2019
    87
    @SeaRecluse get_sum = -10 初始化的时候,写错了
    biossun
    biossun
    Jan 21, 2019
    88
    把 100 进行 10 等分,两两之间随机偏移一下。
    seven777
    seven777
    Jan 21, 2019
    89
    @Linxing
    这个方法更简明易懂。
    xpresslink
    xpresslink
    Jan 21, 2019
    90
    @jssyxzy 你说的办法理论上是可行的,但是实践中是不可用的。
    生成的 9 个随机数之和大于 100 的概率太大了,要远远大于正好小于 100 的概率,所以就要反复生成直要碰上符合条件的,极端情况下上秒出不了结果的可能都有,算法时间复杂度不可控制。

    还是 3 楼方法科学一些。
    shintendo
    shintendo
    Jan 21, 2019
    91
    @SeaRecluse
    还是老哥考虑仔细
    xpresslink
    xpresslink
    Jan 21, 2019
    92
    @seven777 那个方法是很垃圾的方法
    我试验了一下,连续生成的 9 个 1-100 的随机数之和小于 100 的概率是上百万分之一。
    wqzjk393
    wqzjk393
    Jan 21, 2019
    93
    随机取 10 个点,按从小到大排序。取最大的一个放大到 100,其余的根据这个放大比例放大。最后的返回的 10 个随机数就是这 10 个点的间隔,就是 x[10]-x[9],x[9]-x[8]....x[0]
    shuson
    shuson
    Jan 21, 2019
    94
    total = 10
    count = 10

    nTotal = total * 10

    from random import randint

    for i in range(10):
    if nTotal < 1: break
    n = randint(1, nTotal)
    while n + (10 - i) > nTotal:
    n = randint(1, nTotal)

    nTotal -= n
    print("person " + str(i) + " got " + str(n/10) + " dollar")
    imaple
    imaple
    Jan 21, 2019
    95
    拿个秒表然后 100 秒内点 9 下暂停 https://www.v2ex.com/static/img/doge.gif
    jssyxzy
    jssyxzy
    Jan 21, 2019
    96
    @nicking
    @xpresslink
    @NotFamous 已经给出细节了,见他括号内
    wjfz
    wjfz
    Jan 21, 2019
    97
    你这不是“像”,感觉就“是”啊。
    wjfz
    wjfz
    Jan 21, 2019
    98
    哎哟没发完提交了。

    前两天帮朋友解决了这么一个需求,最后也是靠红包算法解决的。

    要求给一个数字,如 15.14
    再给一个浮动范围,± 0.03

    求 5 个数字在浮动范围内,并且平均值==15.14
    LifStge
    LifStge
    Jan 21, 2019 via iPhone
    99
    大小为 10 的数组 选个分布合适的随机函数 循环 100 次 范围 0_99 然后指定下标+1 吧 哈哈哈哈
    kart891209
    kart891209
    Jan 21, 2019
    100
    随机 9 个数,每次 random 的 bound 是(剩余可取的数值+剩余坑数)最后一个减法即可
    1  2  
    ❮ ❯
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2166 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 283ms · UTC 14:33 · PVG 22:33 · LAX 06:33 · JFK 09:33
    ♥ Do have faith in what you're doing.