微信红包接龙的数学分析
春节期间,很多微信群,一夜间变成了“红包群”。微信中的“拼手气红包”带有随机性,随机性增加了参与抢红包的刺激性和娱乐性,甚至被人利用当成“赌博”的道具。
本来中国人过年,发红包是常事,图喜庆,开心,也无需计较什么得失。但在有些微信群里,搞红包接龙,则使得红包变味。
玩法1:群主先发S元红包,随机分成n份(n为群里人数),手气最佳者(即抢得红包最大者)继续发红包,也为S元,n份,下一个手气最佳者继续……
这种玩法较为简单。从短期来看,每人每次抢得红包金额有多有少。从长期来看,每玩一次,每人抢得金额的最大可能性为S/n元;而每次抢,都有可能成为手气最佳者,可能性为1/n,需要接着发出S元红包。这样看来,每人每次收益的期望值是:S/n-1/n×S=0。长期来看,这样玩法属于零和游戏,大家没输没赢。当然这只是理论分析,事实上会有些差别。
如果只是图个乐呵,可以用上述玩法。但如果考虑得失,就会有问题了。因为要长期来看,大家才是基本持平。但短期来看呢,譬如取极端值,只玩一次,第一个发红包的群主不就亏了么?就算再多玩几次,群主也很难回本。于是群主提出要抽成。
玩法2:群主先发S元红包,随机分成n份(n为群里人数),手气最佳者(即抢得红包最大者)需要向群主交“好运费”a元,然后继续发红包,为S元,n份,下一个手气最佳者继续……
这样,从长期来看,每人每次抢得金额的最大可能性为S/n元;而每次抢,都有可能成为手气最佳者,可能性为1/n,需要接着发出S元红包,交“好运费”a元。也就是每人每次收益的期望值为:S/n-1/n×(S+a)=-a/n。这样分析就会发现,看似每一次抢红包,各人抢多抢少,有输有赢,实则每个人都是输家,每次输a/n,这钱被群主赚了。玩得次数越多,群主一人独赚的可能性就越大。当然这只是理论分析,事实上会有些差别。
还有其他的玩法,譬如手气最佳者特定倍数接龙。群主率先在群内发出第一个拼手气红包(几个至几十个不等),手气最佳者按照所获得的金额乘以相应的倍数(从几倍到几十倍不等)接力发红包,以此类推,不断循环。
这样玩分析起来就更复杂了。但总的一条,如果微信系统是真的随机,玩家也没人作弊,也没抽成,即钱总是转来转去的话,那么最终基本上是持平的。但一旦有抽成,哪怕每次抽很少,最后所有赌资都将流向群主一人。
突发奇想给校友微信群发了红包,我设定红包总额为10元,支持28个人随机领取
于是一个有趣的结果出现了
A 领取了 0.26元
B 领取了 0.29元
C 领取了 0.02元
D 领取了 0.56元
E 领取了 0.64元
……
微信是采用什么样的算法做到的?简单百度了下,目前尚未有官方的说明,仅仅在知乎里有一个较为热门的讨论《微信红包的随机算法是怎样实现的?》,链接,https://www.zhihu.com/question/22625187 不过他们讨论的太过于深入,有掉坑之嫌。
我按照自己的逻辑尝试了下,这个算法需要满足以下几点要求
1、每个人都要能够领取到红包;
2、每个人领取到的红包金额总和=总金额;
3、每个人领取到的红包金额不等,但也不能差的太离谱,不然就没趣味;
4、算法一定要简单,不然对不起腾讯这个招牌;
正式编码之前,先搭建一个递进的模型来分析规律
设定总金额为10元,有N个人随机领取:
N=1
则红包金额=X元;
N=2
为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数
第二个红包=10-第一个红包金额;
N=3
红包1=0.01至0.98之间的某个随机数
红包2=0.01至(10-红包1-0.01)的某个随机数
红包3=10-红包1-红包2
……
至此,规律出现啦!开始编码!
header("Content-Type: text/html;charset=utf-8");//输出不乱码,你懂的
$total=10;//红包总额
$num=8;// 分成8个红包,支持8人随机领取
$min=0.01;//每个人最少能收到0.01元
for ($i=1;$i<$num;$i++)
{
$safe_total=$total-($num-$i)*$min;//随机安全上限
$money=mt_rand($min*100,$safe_total*100)/100;
$total=$total-$money;
echo ‘第‘.$i.‘个红包:‘.$money.‘ 元,余额:‘.$total.‘ 元 <br/>‘;
}
echo ‘第‘.$num.‘个红包:‘.$total.‘ 元,余额:0 元‘;
输入一看,波动太大,这数据太无趣了!
第1个红包:7.48 元,余额:2.52 元
第2个红包:1.9 元,余额:0.62 元
第3个红包:0.49 元,余额:0.13 元
第4个红包:0.04 元,余额:0.09 元
第5个红包:0.03 元,余额:0.06 元
第6个红包:0.03 元,余额:0.03 元
第7个红包:0.01 元,余额:0.02 元
第8个红包:0.02 元,余额:0 元
改良一下,将平均值作为随机安全上限来控制波动差
header("Content-Type: text/html;charset=utf-8");//输出不乱码,你懂的
$total=10;//红包总额
$num=8;// 分成8个红包,支持8人随机领取
$min=0.01;//每个人最少能收到0.01元
for ($i=1;$i<$num;$i++)
{
$safe_total=($total-($num-$i)*$min)/($num-$i);//随机安全上限
$money=mt_rand($min*100,$safe_total*100)/100;
$total=$total-$money;
echo ‘第‘.$i.‘个红包:‘.$money.‘ 元,余额:‘.$total.‘ 元 <br/>‘;
}
echo ‘第‘.$num.‘个红包:‘.$total.‘ 元,余额:0 元‘;
输出结果见下图
第1个红包:0.06 元,余额:9.94 元
第2个红包:1.55 元,余额:8.39 元
第3个红包:0.25 元,余额:8.14 元
第4个红包:0.98 元,余额:7.16 元
第5个红包:1.88 元,余额:5.28 元
第6个红包:1.92 元,余额:3.36 元
第7个红包:2.98 元,余额:0.38 元
第8个红包:0.38 元,余额:0 元
参考:http://blog.cqcoder.com/微信红包的算法实现探讨/
原文:http://blog.csdn.net/mrzhoug/article/details/51367118