红包算法相关探究

之前也跟一些讨论过随机红包分配这个问题,自己想了几个方案,但感觉都不太合理,比如无法保证每个人都能得到,以及每个人的期望都一样等等。
在知乎上看到有人说是问过微信的人,大致是随机范围为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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值