来自:Small
链接:http://blog.cqcoder.com/微信红包的算法实现探讨/
突发奇想给校友微信群发了红包,我设定红包总额为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 ……
至此,规律出现啦!开始编码!
C++
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<time.h>
using namespace std;
int main()
{
cout<<"\t\t抢红包游戏"<<endl;
int total;
double totalnum,Min=0.01;//最少能收到0.01元
cout<<"输入红包总数和总金额"<<endl;
scanf("%d%lf",&total,&totalnum);
srand((unsigned)time(NULL));
for(int i=1;i<total;++i)
{
double safe_total=(totalnum-(total-i)*Min);
double num1=((rand()%(int(safe_total*100)-int(Min*100)))+int(Min*100))/100.0;
totalnum-=num1;
cout<<"第"<<i<<"个红包:\t"<<num1<<"元\t"<<"余额:\t"<<totalnum<<"元"<<endl;
}
cout<<"第"<<total<<"个红包:\t"<<totalnum<<"元\t"<<"余额:\t"<<"0元"<<endl;
}
输入一看,波动太大,这数据太无趣了!
抢红包游戏
输入红包总数和总金额
8 30
第1个红包: 3.76元 余额: 26.24元
第2个红包: 21.59元 余额: 4.65元
第3个红包: 2.61元 余额: 2.04元
第4个红包: 1.96元 余额: 0.08元
第5个红包: 0.02元 余额: 0.06元
第6个红包: 0.02元 余额: 0.04元
第7个红包: 0.02元 余额: 0.02元
第8个红包: 0.02元 余额: 0元
改良一下,将平均值作为随机安全上限来控制波动差
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<time.h>
using namespace std;
int main()
{
cout<<"\t\t抢红包游戏"<<endl;
int total;
double totalnum,Min=0.01;//最少能收到0.01元
cout<<"输入红包总数和总金额"<<endl;
scanf("%d%lf",&total,&totalnum);
srand((unsigned)time(NULL));
for(int i=1;i<total;++i)
{
double safe_total=(totalnum-(total-i)*Min)/(total-i);
double num1=((rand()%(int(safe_total*100)-int(Min*100)))+int(Min*100))/100.0;
totalnum-=num1;
cout<<"第"<<i<<"个红包:\t"<<num1<<"元\t"<<"余额:\t"<<totalnum<<"元"<<endl;
}
cout<<"第"<<total<<"个红包:\t"<<totalnum<<"元\t"<<"余额:\t"<<"0元"<<endl;
}
输出结果见下图
抢红包游戏
输入红包总数和总金额
8 30
第1个红包: 1.36元 余额: 28.64元
第2个红包: 0.86元 余额: 27.78元
第3个红包: 4.13元 余额: 23.65元
第4个红包: 4.93元 余额: 18.72元
第5个红包: 0.49元 余额: 18.23元
第6个红包: 8.85元 余额: 9.38元
第7个红包: 7.6元 余额: 1.78元
第8个红包: 1.78元 余额: 0元