微信红包的算法实现

来自: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元




评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值