红包算法相关探究

来源:互联网 发布:linux显示绝对路径 编辑:程序博客网 时间:2024/04/30 19:24

之前也跟一些讨论过随机红包分配这个问题,自己想了几个方案,但感觉都不太合理,比如无法保证每个人都能得到,以及每个人的期望都一样等等。
在知乎上看到有人说是问过微信的人,大致是随机范围为0.01~当前期望*2之间。于是实现了一下,并做了一些简单的探究。

public class HongBao {    public static final int NUM = 20;    public static final BigDecimal AMOUNT = new BigDecimal(200);    public static final BigDecimal MIN_VALUE = new BigDecimal(0.01);    public static final int SCALE = 2;    public static final int MODE = BigDecimal.ROUND_UP;    public static final int RUN = 5000;    public static void main(String[] args) {        BigDecimal[] array = new BigDecimal[NUM];        for (int i = 0; i < NUM; i++) {            array[i] = BigDecimal.ZERO;        }        for (int run = 0; run < RUN; run++) {            BigDecimal remain = AMOUNT.setScale(SCALE, MODE);            // BigDecimal total = BigDecimal.ZERO.setScale(SCALE, MODE);            BigDecimal bestAmount = BigDecimal.ZERO;            int bestPosition = 0;            for (int i = 0; i < NUM; i++) {                BigDecimal current;                if (i == NUM - 1) {                    current = remain;                    // total = total.add(remain);                    // System.out.println(remain.toString());                    // System.out.println("total:" + total.toString());                } else {                    BigDecimal max = remain.divide(new BigDecimal(NUM - i), SCALE, MODE).multiply(new BigDecimal(2));                    current = max.subtract(MIN_VALUE).multiply(new BigDecimal(Math.random())).add(MIN_VALUE)                            .setScale(SCALE, MODE);                    // total = total.add(current);                    // System.out.println(current.toString() + "max:" +                    // max.toString());                }                remain = remain.subtract(current);                array[i] = array[i].add(current);                if (current.compareTo(bestAmount) == 1) {                    bestAmount = current;                    bestPosition = i;                }            }            System.out.println(bestPosition + "," + bestAmount.toString());        }        for (int i = 0; i < NUM; i++) {            //System.out.println(array[i].toString());        }    }}

以200块发20份为例,一次的结果如下:
一次结果

运行1000次的结果,每个人的期望为200/20*1000=10000,大致没有问题
100次结果

最佳手气

一般大家比较好奇的是在第几位开红包,容易出大的。在平常收发红包的过程中,感觉大红包一般都是在后面出现概率较高。
由于数学推导我完全不懂,那么我就拿程序也来做做测试,运行1000次,看看第几次开为最佳手气
1000次最佳统计
从这里看到是后面的会大一些,与平常的感觉类似,那再看看2000次的
2000次最佳统计
嗯,依旧是靠后的获得最佳的会多一些,并且后面和前面的差距也比较大了。峰值居然还是出现在了倒数第二次

不信邪,继续5000次
5000次最佳统计
中间波谷,两头波峰的情况已经有点显现

最后试试30000次,其实没有太大区别了,基本的走势是一致的,中部低,尾部高。
30000次最佳统计

下面是10人5000次与30人15000次
10人
30人
基本的趋势没有变化, 并且人数越多的情况下,波峰会越明显,那么是不是可以说,想要多拿手气最佳,最后两次拿就行了呢。
还得补充一下,手气最佳并不是代表最赚,如果每次都是最后两次拿的话,总的金额也都差不多的,即看第二张图期望其实是一样的。

怎样赚

平常最常玩的就是大家抢完后,最佳手气的再发。以这个为前提,进行一下探索。
首先,第一个拿的人,随机范围是0.01~期望*2,并且此时期望为整体期望,所以其分布应该是最为平均的。(测试10000次,分为20个金额区间统计,则每个区间数量大约为500个)
第一次拿的人的金额分布

但是后面拿的人会受到前面的人拿的影响,总体期望虽然一致,但可能在分布上并不是那么均匀。

直接模拟最佳手气的人继续发的场景,最后成果如下:
手机最佳模拟

所以,大家都应该明白怎么做了吧

0 0
原创粉丝点击