lvgitt / RedPacketAllocated

在微信群里面发红包,每个人能拿到多少钱呢?这个数额是怎样算出来的呢?这个算法告诉你!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

微信红包分配算法

对于微信群发红包,大家再熟悉不过了。除了抢红包最疯狂的春节,平时遇上节日、庆典、生日,都会发红包表示祝贺。比起普通红包每人等额的“平均主义”,大家显然更喜欢手气红包拼运气带来的刺激。然后大家就会炫耀或者哀叹自己的手气,无形中增加了不少社交话题。

从产品角度看,维系用户感情是社交软件的宗旨,微信红包增进社交话题,提升用户间感情,恰好能提高用户粘度,从而反哺对软件的依赖。心理学上研究,抢红包行为有很明显的赌徒心理,希望自己的运气能帮助自己获得尽可能多的未知收益。所以会有“手气不好的想扭转,手气好的想继续”的心理表征,使得微信抢红包一时风头无两。

于是大家就会关心这样的问题:如何在微信群手气红包里抢到尽可能多的钱呢?在什么时机抢是最合理的呢?要想弄明白这些,我们不妨先了解:微信群每个手气红包的数额是怎样计算出来的?这里有一个很科学的算法,下面就由我来给你娓娓道来。
讲解例子:1元分配给20个人

初始化红包

在微信抢过红包的细心朋友都会发现,每个红包的金额即使再小,下限也是1分钱,不可能是0元或者更少。所以红包分配算法做初始化的时候,必须先保证每个红包都不能出现0元或负数。我们可以先给每个红包分配一分钱,如例子所示,系统就会先拿出2角,分给这些用户每人1分钱,剩下的8角再进行后续分配。这样,就保证了每个红包至少1分钱的入账。

结合上述分析,每个人至少一分钱,则n人的红包总数额不能低于n分钱。系统会在分配前做判断,若不能保证每个红包至少一分钱,如4分钱分给5个人,系统就会报错,分配算法提前终止。

系统报错代码

生成随机数

上一步我们介绍了,先给每个人分配1分钱,接下来再分配剩下的8角(allocateSum)。8角等于80分钱,因此系统先随机生成20个0到80的随机数(randNum数组),这一趟循环还需要对随机数求和(randSum)。

随机数求和代码

分配原则是:每个随机数占随机数和的比例,跟每个红包放的钱占总分配钱(即本例的8角)的比例是一样的。所以,每个红包分配到的金额数,可以先用数组中与自己对应的随机数(例如你是第8个人,那就是randNum[7])除以随机数和(randSum),得出比值,再乘以可分配数额(allocateSum)得出。因为金额的最小单位是分,所以需要做四舍五入。加上最初固定的1分钱,那所有红包的数额都计算出来了。

公式

可是,真的有这么简单吗?

末位特殊处理

上述算法提到有一个重要的操作,四舍五入。显然,直接做四舍五入不能保证分配到的金额总数刚好就等于可分配金额数。原因很简单,每个数做四舍五入,都带有一定的随机性,可能增加也可能舍去,但增加与舍去不能保证完全相等。但金钱非常注意严谨,不可能出现发红包的数额跟每个人领到的数目之和不一样的尴尬情况!

末位处理代码

很简单的解决办法是,对于前面n-1个红包采用上述随机数比值的分配方式,最后一个红包就不用这种方式了,改为拿可分配金额数减去之前n-1个红包已经分配的金额数。也就是说,前面n-1个分配完,剩下的都会留给最后一个红包。这样,就能确保每个红包分配到的总数跟可分配总数一样了。至于最后一个红包对应的随机数,只对随机数和有影响,对该红包分配到的金额数没影响(计算方法并不用到它)。

最后一个红包的特殊处理
那现在我能说,这个算法就是完美的吗?

极端情况

这里可能就是大家很关心的问题了。想着如何钻程序bug的空子呢?不知道大家有木有发现这样的现象——通常最佳手气出现在最后一个领红包的人身上。所以,当你时机选择得很好的时候,就可能在看似随机的红包里面抢到比别人更多的money。

当然,这样的现象不无道理,看看这个图片就知道了。(假如我想把6分钱分给5个人) 6分钱分给5个人

解析上述现象,随机数算法为5个红包生成的随机数,大致来说占随机数和的比例都在1/5左右(当然会有起伏,但差别不大)。而除去每个人本来可以分配的1分钱之后,本来可分配的数额就剩下1分钱(另外5分钱按每人1分钱固定分配,6-5×1)。1分钱的五分之一,自然会按四舍五入的原则去掉,导致前4个红包分配到的数额是0。再按照末位特殊处理,可分配的1分钱自然落入最后一个红包里面,造成了分配不公平的假象。

换言之,极端情况,就是在红包总数额(按分钱算)比人数仅多一点点的情况。如12分钱分给10个人(2分钱的1/10),105分钱分给100个人(5分钱的1%)等。这样,前n-1个人只能拿到固定分配的1分钱。可分配的部分数额(allocateSum)本来就少,按随机数比例分配便会更小,最终都因四舍五入而被舍弃。于是,末位特殊处理机制便使多出来但无法分配的一小部分落入最后一个红包。

105分钱分给100个人 105分钱分给100个人

手气红包的规律

其实,微信红包的金额分配算法,还有一些学问。当总数额越大且参与分配的人数越少时,每个红包之间的金额差别也越大。

这个其实和数学里面的正态分布原理是类似的。当参与分配的人很多,而且数额少时,每个红包分配到的金额基本稳定在平均数附近,因此红包金额之间的差距就不大了。数学上理解是,出现概率极低的极端随机数(就是特别大或者特别小的随机数)占随机数和的比重较小(因为人数多,总和大),被其他众多的正常随机数拉到接近平均水平。

但当分配人数较少时,若出现极端随机数而其他正常随机数太少无法调节,它与其他随机数形成鲜明对比,显得“鹤立鸡群”。再夸张地说,如果你发的这个红包数额很大,那差距会等比例放大。

所以,手气红包还是要玩心跳才刺激!要么天堂要么地狱,然后就会有人在朋友圈晒出自己的糟糕手气了。(对,说的就是下图200块却只分到4块钱的那个人!)
手气红包心跳

总结

总体来说,微信红包的分配算法能很大程度上保证每个红包数额的公平性,最佳手气落在每一个红包上的概率都是相等的。毕竟,n个红包里面哪个随机数最大,本来就是一个很随机的事情。只是对于上述的极端情况,最后一个红包是最佳手气的概率陡增。但从行为上来说,你不可能在拿红包之前就知道它属于极端情况,同样也不可能知道你拿的红包是不是最后一个,这个时机本来就很难掐准。再说,极端情况多出来的也就几分钱(上述分析的极小的数额),不见得你会为了多拿这几分钱而高兴许久。

知道了微信红包分配算法就能抢到更多的红包?No way!妄想通过手段获得更多收益,那是欺骗行为。还是现实一点吧,世上本没有不劳而获的东西呢。

如果发现代码有其他bug,或者算法还有其他问题,可以提出issue和pull request哟!

About

在微信群里面发红包,每个人能拿到多少钱呢?这个数额是怎样算出来的呢?这个算法告诉你!


Languages

Language:Java 100.0%