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