如何把 100 块钱随机地分成 30 份呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
crist
V2EX    问与答

如何把 100 块钱随机地分成 30 份呢?

  •  
  •   crist2017 年 4 月 26 日 10737 次点击
    这是一个创建于 3267 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如何把 100 块钱随机地分成 30 份,也就是每一份的钱是不固定的,但是总数加起来必须等于 100 。
    68 条回复    2017-04-28 18:02:45 +08:00
    starvedcat
        1
    starvedcat  
       2017 年 4 月 26 日   13
    取 29 个(0, 100)的坐标
    hinate
        2
    hinate  
       2017 年 4 月 26 日
    xialdj
        3
    xialdj  
       2017 年 4 月 26 日 via iPhone   5
    随便生成 30 个随机数 按照总和与 100 的比例 所有数字等比例缩放
    crist
        4
    crist  
    OP
       2017 年 4 月 26 日
    @hinate 知乎上的回答好复杂啊;
    crist
        5
    crist  
    OP
       2017 年 4 月 26 日
    其实我是这样想的:平均分成 30 份每份 10 元,然后再从这 10 元里面随机抽取几元钱,然后再随机分配给每一份,就 OK 啦
    coderluan
        6
    coderluan  
       2017 年 4 月 26 日
    没特殊要求的话,基本怎么算都能实现吧。
    blankme
        7
    blankme  
       2017 年 4 月 26 日 via Android
    @crist 你要是只需要均匀分布,按一楼说的做就行了
    Vizogood
        8
    Vizogood  
       2017 年 4 月 26 日 via iPhone
    楼主是不是要写一个红包算法 (滑稽
    crist
        9
    crist  
    OP
       2017 年 4 月 26 日   1
    @Vizogood 那请问你有什么妙计没?说出来听听
    crist
        10
    crist  
    OP
       2017 年 4 月 26 日
    @crist 说错了,好像 100 分成 30 份并不是每份 10 哈应该是 3.33333333333333333333333333333 元
    tankb52
        11
    tankb52  
       2017 年 4 月 26 日   1
    建 30 个人的群,发 100 块钱红包啊
    ioriwong
        12
    ioriwong  
       2017 年 4 月 26 日 via Android
    用一楼 挡板法 就行了
    rogerchen
        13
    rogerchen  
       2017 年 4 月 26 日 via Android
    @crist 一楼已经给出真相了
    johnny23
        14
    johnny23  
       2017 年 4 月 26 日 via iPhone
    random100 次 每次都取模 3 结果为 0 给第一份红包加一 为 1 加二个红包 为 2 加第三个红包 不知道这样如何?
    zhangbohun
        15
    zhangbohun  
       2017 年 4 月 26 日 via Android   1
    随机生成三十个数,然后每个除以总和乘以 100 生成前九十九个,最后一个 100 减前面的九十九个。
    johnny23
        16
    johnny23  
       2017 年 4 月 26 日 via iPhone
    看错题目了 楼主可以无视我 哭...
    zhaojjxvi
        17
    zhaojjxvi  
       2017 年 4 月 26 日 via iPhone
    @starvedcat 说实话没太懂怎么保证各项和等于 100
    crist
        18
    crist  
    OP
       2017 年 4 月 26 日
    29 个(0, 100)的坐标怎么取,用什么语言?能否 30 份每一份都是随机数量的?
    johnny23
        19
    johnny23  
       2017 年 4 月 26 日 via iPhone
    改良哈 random ( 30 ) 70 次
    blankme
        20
    blankme  
       2017 年 4 月 26 日 via Android   3
    @crist 29 个(0, 100)随机数,红包金额就是相邻两点随机数之差
    johnny23
        21
    johnny23  
       2017 年 4 月 26 日 via iPhone
    重新来 先从 100 元扣出 30 分分别放在 30 个红包里面一个红包一分钱 然后做 9970 次 random(30 的运算) 随机结果是多少就给对应的红包加一分钱 比如 25 就给第 25 个红包加一分钱 直到 9970 次结束
    SingeeKing
        22
    SingeeKing  
    PRO
       2017 年 4 月 26 日
    找来 29 个人建个群,发 100 元分 30 个包,大家领完记录就好了
    RqPS6rhmP3Nyn3Tm
        23
    RqPS6rhmP3Nyn3Tm  
       2017 年 4 月 26 日 via iPhone
    离散数学基础啊哥
    crist
        24
    crist  
    OP
       2017 年 4 月 26 日
    @johnny23 根据你的描述,应该随机 100 次就已经结束了,为什么还要随机 9970 次呢?除非你是想把 100 块分成 9970 份啊,这样也是 OK 的,不过太耗费资源了,分成 500 个小份再随机加到 30 个红包里面就可以了。点子不错,谢谢你~~
    libook
        25
    libook  
       2017 年 4 月 26 日
    循环随机二分?
    循环 29 次,每次把剩下的钱随机分成两份,一份分出去,另一份进入下一次循环。

    不知道在概率学上和 1 楼的区别,有大牛来讲一下吗?
    blankme
        26
    blankme  
       2017 年 4 月 26 日   1
    @libook 1 楼是最标准的做法,每份的期望值都是 100/30.
    你的做法得到的每份红包期望值都不一样,比如第一份是 50.
    acros
        27
    acros  
       2017 年 4 月 26 日
    困扰的主要是红包带来的潜在限制条件吧 分的平均了没意思,大小太极端不行。

    所以这个做好后还需要测试下,最好建个群分真钱测试,这样可以如实调研用户心理。
    --- 楼主建好这个群后请务必加我。我有时间帮你测试!
    jiangzhuo
        28
    jiangzhuo  
       2017 年 4 月 26 日
    楼上说发红包的方法,如果有人不领红包怎么能保证我最后得到 30 个数字。
    crist
        29
    crist  
    OP
       2017 年 4 月 26 日
    $total = 100;

    $pr = 1000; // 分成小份数

    $bit = total / $pr;

    $array = [];

    for ($i=0; $i < $pr; $i++) {

    $array[rand(0,29)] += $bit;
    }

    echo "<pre>";print_r($array);
    echo "total = " . array_sum($array);
    vicalloy
        30
    vicalloy  
       2017 年 4 月 26 日
    最主要的问题是每次分完后,剩下的前足够余下的人分。
    简单的写了一下,可能会有 bug

    https://gist.github.com/vicalloy/7225cf8749e427882e0e70138353739a
    johnny23
        31
    johnny23  
       2017 年 4 月 26 日 via iPhone
    @crist 分细的原因只是钱最小单位是分....至于这个单位如何取舍 可以自己控制
    johnny23
        32
    johnny23  
       2017 年 4 月 26 日 via iPhone
    @crist 因为以前抢红包抢过 1 分钱...所以
    lygmqkl
        33
    lygmqkl  
       2017 年 4 月 26 日
    我贡献一个思路,首先要看细分的程度,如果每个人都要有,而且粒度到 1 元,那么就
    第一轮先每人给 1 块,剩下 70 元,再进入第二轮
    第二轮拿出 30 元,每人 mt_rand(0,1), 如果 0 则不分配,如果 1 则分配 1 元,余下未分配的放回奖池
    第三,第四,第五轮, repeat 第二轮

    理论上 第三轮结束,应该已经分配出去 90 元, 所以还是很快的。

    如果是要到 0.01 ,那么就以 10000 为基数,第一轮每人 1 , 剩下每轮 0-3000 也可以 0-1000 ,多跑几个循环即可。

    理论上结果应该和一楼隔板法很接近,其实我是赞同一楼的,但是这种以轮为单位的方法感觉也 ok ,并没有多跑几次,而且看起来更均匀和公平。
    ifishman
        34
    ifishman  
       2017 年 4 月 26 日 via Android
    @blankme 确定一楼的总数是 100 ?
    viator42
        35
    viator42  
       2017 年 4 月 26 日
    取一个 0 到 100 的随机数,这个数作为第一份,然后 100 减去这个数,剩下的钱再随机,29 次之后剩下的钱作为第三十份
    ifishman
        36
    ifishman  
       2017 年 4 月 26 日 via Android
    @blankme 既然楼主需要的是红包算法,那就不能采用相同期望值的算法,红包就应该是第一个人抢的时候最容易抢最多的,第二个次之……
    Domains
        37
    Domains  
       2017 年 4 月 26 日
    这不就是红包?
    理论要看实践
    到我这都 36 楼了,要不 LZ 开个群, 100 发个 30 人红包,每次统计好,发一百次
    Domains
        38
    Domains  
       2017 年 4 月 26 日
    @ifishman 你要是真抢过红包,你就知道错得过分,抢红包出现在中后段出现的金额普遍较高。另,这真有实践题,有人就专门测试过的,金额高于平均值的普遍出现于中段后
    Monad
        39
    Monad  
       2017 年 4 月 26 日
    直接插板法就好了 高中数学
    srlp
        40
    srlp  
       2017 年 4 月 26 日
    太复习了。均匀的话,一楼的足够。


    @ifishman 一楼的意思是,标记了 29 个挡板之后,每个红包的钱数是两个挡板之间的距离。加起来显然是 100 。
    Vizogood
        41
    Vizogood  
       2017 年 4 月 26 日 via iPhone
    @crist https://www.zhihu.com/question/22625187
    我没有什么好的算法 原来在知乎上看过一个类似问题
    crist
        42
    crist  
    OP
       2017 年 4 月 26 日
    29 楼我那个方法有点缺陷哈:就是结果起伏变化不是很大, 100 块钱 30 份的每一份都很少有低于 2.0 或者高于 4.0 的
    blankme
        43
    blankme  
       2017 年 4 月 26 日
    @ifishman 确定,区间多大,总数就多大,这不是显而易见的吗。。
    wbt
        44
    wbt  
       2017 年 4 月 26 日
    随机生成 30 个( 0-1 之间的)数字,然后求和计算每个数字的百分比,最后乘以 100 。
    rogerchen
        45
    rogerchen  
       2017 年 4 月 26 日 via Android
    #1 隔板法
    #14 正则化
    两个都是好方法,正则化可以完全控制分布
    slixurd
        46
    slixurd  
       2017 年 4 月 26 日
    "首先,我来讨论一下为什么要采用截尾正态分布。首先介绍一种更加直接的方法(我有一些朋友也这样猜测):如果我有 50 元,要发给 25 人。那么我用连续均匀分布随机产生 24 个位于 0 到 50 之间的数字。这 24 个数字将整个 0-50 的区间划分为 25 份,分别分给这 25 个人。但事实并不是这样的。学过序列统计的人应该知道,由于这 24 个点是连续均匀分布产生的,因此他们的序列统计量也是连续均匀分布产生的,因此他们之间的间隔的分布是指数分布的。具体证明从略,可参照 John Rice 2007 。

    作者: Mr.L
    链接: https://www.zhihu.com/question/22625187/answer/85431684
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。"
    nszm
        47
    nszm  
       2017 年 4 月 26 日
    @crist #42 有可能分不到吗....
    qxd123
        48
    qxd123  
       2017 年 4 月 26 日
    关于这个问题,如果单纯为了每个人获得的金额都相差不大的话,用一楼的确实就够用了,但如果要想跟微信红包差不多的结果,用正态分布的算法来更为合理,楼上也都给出了些方法,在保证大部分人的金额处于平均数附近,但是又有极少人的金额是相对大一点或者小一点,另外之前在网上看到过类似这种的,可以参考看看 https://segmentfault.com/q/1010000006002081
    geelaw
        49
    geelaw  
       2017 年 4 月 26 日
    你这个问题根本不是 well-asked ,都不知道你想要什么分布,怎么随机?
    di94sh
        50
    di94sh  
       2017 年 4 月 26 日 via Android
    就一楼的方法, 10000 里面生成 29 个不想等的随机数,大小排序,从零开始判断区间。/100 可以精确到分。
    fl2d
        51
    fl2d  
       2017 年 4 月 26 日
    你要的是啥分布的随机,这很重要
    wangleineo
        52
    wangleineo  
       2017 年 4 月 26 日
    实践出真知,楼主建个群发红包,看看微信红包到底什么分布。
    zjp
        53
    zjp  
       2017 年 4 月 26 日 via Android
    是我想的太简单吗 #15 的方法不就可以了吗
    yellowV2ex
        54
    yellowV2ex  
       2017 年 4 月 26 日
    随机 100 个数记下来,再计算他们的和,然后每一份的钱就是

    每一个随机数
    ------------------- x 100.00
    所有随机数总和
    qqjt
        55
    qqjt  
       2017 年 4 月 26 日
    钱应该最小是 0.01 , 0-100 间有 999 个取值,问题变成了 [1-999]里面随机取 30 个整数。
    qqjt
        56
    qqjt  
       2017 年 4 月 26 日
    @qqjt 不对是取 29 个。
    Actrace
        57
    Actrace  
       2017 年 4 月 26 日   1
    既然入坑了,我就贴一下代码把。。
    ```````````
    <?php
    $total = 10000;//总额,按分
    $max = 500;//最大可分额度
    $min = 100;//最小可分额度
    $times = 30;//分几个人
    for($i=1;$i<=$times;$i++){
    $exp = ($total-($times-$i))>$max?$max:($total-($times-$i));
    $now = rand($min, $exp);
    $total = $total - $now;
    $f1 = $now/100;
    $f2 = $total/100;
    echo "//第{$i}个人:{$f1}元,剩余{$f2}元。\n";
    }
    echo "//第 30 个人:{$f2}元。\n";
    ?>
    ````````````
    //第 1 个人:3.69 元,剩余 96.31 元。
    //第 2 个人:2.82 元,剩余 93.49 元。
    //第 3 个人:4.79 元,剩余 88.7 元。
    //第 4 个人:3.57 元,剩余 85.13 元。
    //第 5 个人:4.39 元,剩余 80.74 元。
    //第 6 个人:2.45 元,剩余 78.29 元。
    //第 7 个人:2.1 元,剩余 76.19 元。
    //第 8 个人:4.89 元,剩余 71.3 元。
    //第 9 个人:4.93 元,剩余 66.37 元。
    //第 10 个人:4.19 元,剩余 62.18 元。
    //第 11 个人:2.2 元,剩余 59.98 元。
    //第 12 个人:4.52 元,剩余 55.46 元。
    //第 13 个人:4.67 元,剩余 50.79 元。
    //第 14 个人:3.92 元,剩余 46.87 元。
    //第 15 个人:3.44 元,剩余 43.43 元。
    //第 16 个人:1.32 元,剩余 42.11 元。
    //第 17 个人:1 元,剩余 41.11 元。
    //第 18 个人:3.52 元,剩余 37.59 元。
    //第 19 个人:2.21 元,剩余 35.38 元。
    //第 20 个人:4.19 元,剩余 31.19 元。
    //第 21 个人:1.29 元,剩余 29.9 元。
    //第 22 个人:2.87 元,剩余 27.03 元。
    //第 23 个人:4.88 元,剩余 22.15 元。
    //第 24 个人:3.98 元,剩余 18.17 元。
    //第 25 个人:2.93 元,剩余 15.24 元。
    //第 26 个人:3.83 元,剩余 11.41 元。
    //第 27 个人:3.82 元,剩余 7.59 元。
    //第 28 个人:1.57 元,剩余 6.02 元。
    //第 29 个人:1.26 元,剩余 4.76 元。
    //第 30 个人:2.2 元,剩余 2.56 元。
    //第 30 个人:2.56 元。
    Actrace
        58
    Actrace  
       2017 年 4 月 26 日
    过大的粒度可能会让结果偏离更大,比如一个人拿了 99 块钱。。
    过小的粒度同样如此,最后一个人拿了 99 块钱。。。
    mingyun
        59
    mingyun  
       2017 年 4 月 26 日
    可以参考微信红包算法
    zhihaofans
        60
    zhihaofans  
       2017 年 4 月 26 日
    用 html+js 做了个粗暴的方法,为什么大部分都在前面呢, js 随机算法的原因?

    zander
        61
    zander  
       2017 年 4 月 26 日 via iPhone
    @ifishman 29 个点, 30 个线段。
    imn1
        62
    imn1  
       2017 年 4 月 27 日
    @libook
    @Actrace
    这样分,其实不太合理,因为
    理论上只有第一位有可能获得最高值 99.71 (其他都是 0.01 ),剩下的 29 位均无法获得这个最高值,概率为 0
    而且获得更大值的概率逐次降低
    所以,这样做,必须分配完成后打乱顺序,否则顺位靠前必然占优,即使是随机,概率也是占优的

    使用平均数也是不合理的,因为算出平均数,再做一次腾挪的话,基本上每份的最大值只能是 平均数*2 ,除非做多次腾挪;但这种方法,如果本意是避免落差太大的分配,是可以的
    libook
        63
    libook  
       2017 年 4 月 27 日
    @imn1 所以二分法之后再打乱顺序的话是不是就公平了?
    Actrace
        64
    Actrace  
       2017 年 4 月 27 日
    @imn1 你提到的问题好解决,如果你想要让某个人获得最高值的概率是随机的,可以把红包提前分配好,然后再将分配好的红包配额随机分发给其他人。

    理论上来说,算法本身是合理的,因为随机数函数本身就是随机的。按照微信红包的那种设定,即使第一个人领取了更多的配额,这也是随机的,不存在公平性问题讨论,因为这里的目标是“随机”,实际上第一个领红包的人也是随机的。

    设定 min 和 max 也只是为了让落差有一个可控的程度,也就是说楼主想要“公平”的话,这个是附加福利(可选项)。
    imn1
        65
    imn1  
       2017 年 4 月 27 日
    @libook
    依题目,只要符合一次整体随机就可以了,就是数额和顺序,所以递减逐次随机取数额及随机顺序应该满足
    不过我个人不太喜欢,又说不出什么道理

    个人倾向#15 的权重方法,这种方法是不理会总额的完全随机,再换算成总额 100 的占比

    #1 插板法理论上也是完全随机,但这种方法有个弊端,就是不能在相同位置插两块,所以程序是要限制的
    而#15 则没有这个问题
    imn1
        66
    imn1  
       2017 年 4 月 27 日
    @Actrace
    如上面所说,我也说不出道理
    不过抢红包有点不同,它本身就含有“抢”顺位的意味,所以顺位靠前获得更多的数额,这个概率大点是合理的
    zhangsen1992
        67
    zhangsen1992  
       2017 年 4 月 27 日
    l = [random.randint(0,100) for i in range(30)]
    map(lambda x:100*x/float(sum(l)),l)
    imn1
        68
    imn1  
       2017 年 4 月 28 日
    再补充一下:
    这个不同抽样方法之间的区别就是,每次抽取的样本是否返回样本库,是,则为排列,否,则为组合

    #1 每次取值均不能与前面相同,就是样本不返回样本库
    #15 可以多次相同值,所以是样本返回样本库,而且理论上样本库无限大,只要计算机能处理则可
    而每次扣除取出金额,递减再随机,也是不返回样本库,而且样本库的减少比#1 插板法更甚
    至于平均再腾挪,属于分段抽样法,样本库远小于前面三种

    其实哪种方法都能实现目标(没有离题),看需求选择
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1113 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 182ms UTC 17:30 PVG 01:30 LAX 10:30 JFK 13:30
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86