大家在抢红包,程序员在研究红包算法


Posted in PHP onAugust 31, 2015

除夕全天微信用户红包总发送量达到10.1亿次,摇一摇互动量达到110亿次,红包峰值发送量为8.1亿次/分钟。

抛开微信红包的市场价值不谈,红包本身的算法也引发了热议,由于官方没有给出明确的说法,各家也是众说纷纭,小编下面也为大家带来几种分析。

首先看看数据分析帝

大多数人都做出自己的猜测,这也是在不知道内部随机算法的时候的唯一选择,但是大多数人没有给出自己亲自的调查结果。这里给出一份100样本的调查抽样样本数据,并提出自己的猜测。

1. 钱包钱数满足截尾正态随机数分布。大致为在截尾正态分布中取随机数,并用其求和数除以总价值,获得修正因子,再用修正因子乘上所有的随机数,得到红包价值。

这种分布意味着:低于平均值的红包多,但是离平均值不远;高于平均值的红包少,但是远大于平均值的红包偏多。

大家在抢红包,程序员在研究红包算法

图1. 钱包价值与其频率分布直方图及其正态拟合

但看分布直方图并不能推出它符合正态分布,但是考虑到程序的简洁性和随机数的合理性,这是最合乎情理的一种猜测。
越是后面的钱包,价值普遍更高

大家在抢红包,程序员在研究红包算法

图2. 钱包序列数与其价值关系曲线

从图2中的线性拟合红线可以看到,钱包价值的总体变化趋势是在慢慢增大,其变化范围大约是一个绿色虚线上下界划出的“通道”。(曲线可以被围在这么一个正合乎常规的“通道”中,也从侧面反映了规律1的合理性,说明了并不是均匀分布的随机数)
从另一个平均数的图中也可以看出这一规律。

大家在抢红包,程序员在研究红包算法

图3. 平均数随序列数的变化曲线

在样本中,1000价值的钱包被分成100份,均值为10。然而在图3中我们可以看到在最后一个钱包之前,平均数一直低于10,这就说明了一开始的钱包价值偏低,一直被后期的钱包价值拉着往上走,后期的钱包价值更高。

3. 当然平均数的图还可以透露出另一个规律,那就是最后的那一个人往往容易走运抽得比较多。因为最后那一个人是钱包剩下多少就拿多少的,而之前所有人的平均数 都低于10,所以至少保证了最后一个人会高于平均值。在本样本中,98号钱包抽到35,而最后一份钱包抽到46。

综上,根据样本猜测:

大家在抢红包,程序员在研究红包算法

1. 抽到的钱大多数时候跟别人一样少,但一旦一多,就容易多很多。
2. 越是抽后面的钱包,钱越容易多。
3. 最后一个人往往容易撞大运。

点评:这种明显很实际有差异,小编每次不管什么时候抢都是几毛钱。

第二位同学写了一个简单python 代码

据观察,红包分钱满足以下几点:

1.不会有人拿不到钱

2.不会提前分完

3.钱的波动范围很大

红包在一开始创建的时候,分配方案就订好了。抢红包的时候,不过是挨个pop up而已。

因此 python 代码如下:

def weixin_divide_hongbao(money, n): 
divide_table = [random.randint(1, 10000)
for x in xrange(0, n)] 
sum_ = sum(divide_table) 
return [x*money/sum_ for x in divide_table]

不过上述算法还有两个小问题:

1.浮点数精度问题

2.边界值的处理

第三位同学按照网上流传的python写了一个java的版本

int j=1; 
while(j<1000) 
{ 
int number=10; 
float total=100; 
float money; 
double min=0.01; 
double max; 
int i=1; 
 
List math=new ArrayList(); 
while(i<number) 
{ 
 
max = total- min*(number- i); 
int k = (int)((number-i)/2); 
if (number -i <= 2) 
{k = number -i;} 
max = max/k; 
money=(int)(min*100+Math.random()*(max*100-min*100+1)); 
money=(float)money/100; 
total=total-money; 
math.add(money); 
System.out.println("第"+i+"个人拿到"+money+"剩下"+total); 
i++; 
if(i==number) 
{ 
math.add(total); 
System.out.println("第"+i+"个人拿到"+total+"剩下0"); 
} 
} 
 
System.out.println("本轮发红包中第"+(math.indexOf(Collections.max(math))+1)+"个人手气最佳"); 
j++; 
}

第四位同学的这种算法看起来非常科学。

他认为:

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

……

int j=1; 
while(j<1000) 
{ 
int number=10; 
float total=100; 
float money; 
double min=0.01; 
double max; 
int i=1; 
 
List math=new ArrayList(); 
while(i<number) 
{ 
 
max = total- min*(number- i); 
int k = (int)((number-i)/2); 
if (number -i <= 2) 
{k = number -i;} 
max = max/k; 
money=(int)(min*100+Math.random()*(max*100-min*100+1)); 
money=(float)money/100; 
total=total-money; 
math.add(money); 
System.out.println("第"+i+"个人拿到"+money+"剩下"+total); 
i++; 
if(i==number) 
{ 
math.add(total); 
System.out.println("第"+i+"个人拿到"+total+"剩下0"); 
} 
} 
 
System.out.println("本轮发红包中第"+(math.indexOf(Collections.max(math))+1)+"个人手气最佳"); 
j++; 
}

输入一看,波动太大,这数据太无趣了!

第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 元

改良一下,将平均值作为随机安全上限来控制波动差

int j=1; 
while(j<1000) 
{ 
int number=10; 
float total=100; 
float money; 
double min=0.01; 
double max; 
int i=1; 
 
List math=new ArrayList(); 
while(i<number) 
{ 
 
max = total- min*(number- i); 
int k = (int)((number-i)/2); 
if (number -i <= 2) 
{k = number -i;} 
max = max/k; 
money=(int)(min*100+Math.random()*(max*100-min*100+1)); 
money=(float)money/100; 
total=total-money; 
math.add(money); 
System.out.println("第"+i+"个人拿到"+money+"剩下"+total); 
i++; 
if(i==number) 
{ 
math.add(total); 
System.out.println("第"+i+"个人拿到"+total+"剩下0"); 
} 
} 
 
System.out.println("本轮发红包中第"+(math.indexOf(Collections.max(math))+1)+"个人手气最佳"); 
j++; 
}

输出结果见下图

第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 元

小结:

小编觉得这完全可以理解成一个红包引发的血案,小编仅仅列举了几个,还有一些工程学的同学直接抛出了数学模型、离散函数等等,但是无论算法是简单还是复杂,玩的开心就够了。

PHP 相关文章推荐
使用数据库保存session的方法
Oct 09 PHP
php 修改zen-cart下单和付款流程以防止漏单
Mar 08 PHP
使用XDebug调试及单元测试覆盖率分析
Jan 27 PHP
zend framework多模块多布局配置
Feb 26 PHP
在php和MySql中计算时间差的方法
Apr 22 PHP
基于PHP array数组的教程详解
Jun 05 PHP
PHP中批量生成静态html(命令行下运行PHP)
Apr 19 PHP
php cli换行示例
Apr 22 PHP
PHP将回调函数作用到给定数组单元的方法
Aug 19 PHP
Dwz与thinkphp整合下的数据导出到Excel实例
Dec 04 PHP
PHP结合jQuery实现找回密码
Jul 22 PHP
Laravel路由研究之domain解决多域名问题的方法示例
Apr 04 PHP
微信公众平台开发之天气预报功能
Aug 31 #PHP
百度地图经纬度转换到腾讯地图/Google 对应的经纬度
Aug 28 #PHP
PHP7.0安装笔记整理
Aug 28 #PHP
php中二维数组排序问题方法详解
Aug 28 #PHP
php页面,mysql数据库转utf-8乱码,utf-8编码问题总结
Aug 27 #PHP
PHP生成随机密码方法汇总
Aug 27 #PHP
windows下apache搭建php开发环境
Aug 27 #PHP
You might like
PHP+MYSQL开发工具及资源收藏
2007/01/02 PHP
linux系统上支持php的 iconv()函数的方法
2011/10/01 PHP
smarty实现多级分类的方法
2014/12/05 PHP
详解Yii2 定制表单输入字段的标签和样式
2017/01/04 PHP
关于php几种字符串连接的效率比较(详解)
2017/02/22 PHP
PHP在同一域名下两个不同的项目做独立登录机制详解
2017/09/22 PHP
动态为事件添加js代码示例
2009/02/15 Javascript
让你的博客飘雪花超出屏幕依然看得见
2013/01/04 Javascript
js解析与序列化json数据(二)序列化探讨
2013/02/01 Javascript
JS实现拖拽的方法分析
2016/12/20 Javascript
Vue.js实现模拟微信朋友圈开发demo
2017/04/20 Javascript
如何在 Vue.js 中使用第三方js库
2017/04/25 Javascript
nodejs构建本地web测试服务器 如何解决访问静态资源问题
2017/07/14 NodeJs
JS实现的加减乘除四则运算计算器示例
2017/08/09 Javascript
JavaScript体验异步更好的解决办法
2018/01/08 Javascript
详解angular部署到iis出现404解决方案
2018/08/14 Javascript
JS函数节流和防抖之间的区分和实现详解
2019/01/11 Javascript
小程序云函数调用API接口的方法
2019/05/17 Javascript
three.js显示中文字体与tween应用详析
2021/01/04 Javascript
[01:19]DOTA2城市挑战赛报名开始 开启你的城市传奇
2018/03/23 DOTA
[00:59]DOTA2荣耀之路1:Doom is back!weapon X!
2018/05/22 DOTA
复习Python中的字符串知识点
2015/04/14 Python
Linux下为不同版本python安装第三方库
2016/08/31 Python
Python爬虫通过替换http request header来欺骗浏览器实现登录功能
2018/01/07 Python
Python数据分析之双色球统计单个红和蓝球哪个比例高的方法
2018/02/03 Python
python pycurl验证basic和digest认证的方法
2018/05/02 Python
修改 CentOS 6.x 上默认Python的方法
2019/09/06 Python
Python常用数据类型之间的转换总结
2019/09/06 Python
利用HTML5 Canvas制作键盘及鼠标动画的实例分享
2016/03/15 HTML / CSS
希尔顿酒店中国网站:Hilton中国
2017/03/11 全球购物
ebookers英国:隶属全球最大的在线旅游公司Expedia
2017/12/28 全球购物
英语教育专业毕业生求职信
2014/08/28 职场文书
2015年学校德育工作总结
2015/04/22 职场文书
员工离职证明范本
2015/06/12 职场文书
浅谈Python基础之列表那些事儿
2021/05/11 Python
Promise静态四兄弟实现示例详解
2022/07/07 Javascript