网站换成了HTTPS访问,比以前有逼格了。顺应潮流的使用了Let's encrypt。
最近偶然间想到了红包的分配问题,在这里记录下思路和代码。
问题
发一个N元红包,M人来分,尽量公平每个人拿到的金额。
思路:假设10元红包10个人分,为了保证剩下的人能拿到红包,每个人最大能拿(红包金额-剩余人数*最小金额)的量,但如果每个人都可能拿最大金额,对排在后面的人就不公平,为此需要对取值范围进行调整。
代码一var RedPacket = function(person,money,min){
this.person = person; //人数
this.money = money; //红包金额
this.min = min; //最小金额
this.random = 0; //每次抽到的金额
this.algorithm1 = function(){
for(let i=1;i
let max = this.money-(this.person-i)*min;
let avg;
if(i!=this.person-1){
do{
avg = max/(this.person-i)+[max/(this.person-i)]*(1/2); //取值范围公式
}while(avg>max)
}else{
avg = max;
}
do{
this.random = parseFloat(Math.random()*(avg-min)+min); //抽取avg和min之间的随机数
this.random = Math.floor(this.random*Math.pow(10,2))/Math.pow(10,2); //保留小位数
}while(this.random>avg||this.random
this.money = Math.floor((this.money-this.random)*Math.pow(10,2))/Math.pow(10,2);
console.log("第"+i+"个人拿到了"+this.random+"元钱,还剩"+this.money+"元。");
}
console.log("第"+this.person+"个人拿到了最后的"+this.money+"元钱。");
};
}
测试结果
这个方法每次抽取500次后的结果就如图中所示一样,倒数第二个人之前取得的红包金额量都是递进式的,只有最后两名相对公平。
代码二var RedPacket = function(person,money,min){
this.person = person; //人数
this.money = money; //红包金额
this.min = min; //最小金额
this.random = 0; //每次抽到的金额
this.algorithm2 = function(){
for(let i=this.person;i>1;i--){
let max = this.money-(this.person-1)*this.min;
let avg = i<=2?max:max/i*2; //取值范围公式
do{
this.random = parseFloat(Math.random()*(avg-this.min)+this.min); //抽取avg和min之间的随机数
this.random = Math.floor(this.random*Math.pow(10,2))/Math.pow(10,2);
}while(this.random>avg||this.random
this.money = Math.floor((this.money-this.random)*Math.pow(10,2))/Math.pow(10,2);
console.log("第"+(this.person-i+1)+"个人拿到了"+this.random+"元钱,还剩"+this.money+"元。");
}
console.log("第"+this.person+"个人拿到了最后的"+this.money+"元钱。");
};
}
测试结果
第二种方法就相对平稳了很多,极差小了不少,不过我多次抽取几组后,发现最后一个人还是更容易抽的多些,但如果抽上千次来看的话还是很平均的。
测试地址
多次抽取的话,可以在控制台循环调用method(1)或method(0)方法,分别对应第一个和第二个算法。