首页 > 编程语言 >抢红包随机金额算法(均衡随机)

抢红包随机金额算法(均衡随机)

时间:2024-02-03 14:24:43浏览次数:49  
标签:10 money 抢红包 0.01 金额 算法 随机 100

最优算法在文末,欢迎参考。
编写抢红包随机算法功能,通常金额是红包支付后立马算好的,而不是抢一个实时随机一个红包金额,避免并发情况下降低性能。

需求

仿照微信发红包功能,现有n个人抢金额为m的红包,m>=0.01,n>0,m/n不能小于0.01,需保证每个人都能抢到最低为0.01的金额,金额随机,但金额相对均衡

解决方案

无限制随机(不可取)

假设:10个人抢100元的红包。
操作:前几人无限制随机0.01到最大金额,最后一人兜底剩余金额。
结论:这种算法很不稳定,导致前几人分的很多,后面的人没钱分或者很少分的情况,容易出现极端现象。

function red_envelope($money, $person) {
    for($i = 1; $i <= $person; $i++) {
        if($person === $i) {
            $res[$i]  = $money;
        } else {
            if($money <= 0) {
                $res[$i] = 0;
            } else {
                $res[$i] = bcdiv(mt_rand(1, bcmul($money, 100)),100, 2);
                $money = bcsub($money, $res[$i], 2);
            }
        }
    }
    return $res;
}

演进:均衡分配(凑合)

假设:3个人抢20元的红包。
操作:甲抢到6.66,乙抢到6.66,丙兜底抢剩余的的6.68。
结论:算法简单,但随机性差点。

function red_envelope($money, $person) {
	$div = bcdiv($money, $person, 2);
	for($i = 1; $i <= $person; $i++) {
		$res[$i] = $person === $i ? $money - $div * ($i - 1) : $div;
	}
	return $res;
}

演进:递减法(不可取)

假设:10个人抢100元的红包。
操作:第一个人在0.01-99.1之间,预扣的0.09是供其它9个人使用的,假设第一个人抢了70,那么第二个人就是0.01到(100-70-(8 * 0.01))之间的随机数,最后一人兜底剩余金额。
结论:这种算法仍旧不公平,越到后面,金额越少,导致后面的人没钱分或者很少分,容易出现极端现象。

function red_envelope($money, $person) {
    for($i = 1; $i <= $person; $i++) {
        if($i != $person) {
            //剩余金额 = 总金额 - (最小值 * (总人数 - 当前人数))
            $residue_money = bcsub($money, bcmul(0.01, bcsub($person, $i, 2), 2), 2);
            $res[$i] = bcdiv(mt_rand(1, bcmul($residue_money, 100, 2)), 100, 2);
            $money = bcsub($money, $res[$i], 2);
        } else {
            $res[$i] = $money;
        }
    }
    return $res;
}

演进:无序递减法(不可取)

假设:10个人抢100元的红包。
操作:把上一个方法的顺序打乱。
结论:这种算法仍旧不公平,导致任意某人可能没钱分或者很少分,容易出现极端现象。

$res = red_envelope(100, 10, 0.01);
shuffle($res);

演进:二倍均值法(推荐)

假设:假设10个人抢100元红包。
操作:取0.01~(剩余金额 / 剩余人数 * 2)之间的随机数(2为常数,用于影响结果使其趋向平均值),最后一人兜底剩余金额。
结论:二倍均值法理论上可实现相对均衡的随机金额。

function red_envelope($money, $person) {
    $arr   = [];
    for($i = 0; $i < $person; $i ++) {
        $arr[$i] = $money;
        if($person !== ($i + 1)) {
            $arr[$i]  = bcdiv(mt_rand(1, intval($money / ($person - $i) * 200)), 100, 2);
            $money = bcsub($money, $arr[$i] , 2);
        }
    }
    return $arr;
}

理想情况下平均每人金额在10元上下,以下是模拟:

第几人 下限随机金额 上限随机金额 上限随机金额算法 理论平均金额 实际随机金额
1 0.01 20.00 100 / 10 * 2 10.00 12.25
2 0.01 19.50 87.75 / 9 * 2 9.76 6.87
3 0.01 20.22 80.88 / 8 * 2 10.12 11.22
4 0.01 19.90 69.66 / 7 * 2 9.96 10.01
5 0.01 19.88 59.65 / 6 * 2 9.95 0.85
6 0.01 23.52 58.80 / 5 * 2 11.77 19.56
7 0.01 19.62 39.24 / 4 * 2 9.81 4.23
8 0.01 23.34 35.01 / 3 * 2 11.68 9.85
9 0.01 25.16 25.16 / 2 * 2 12.59 12.59
10 12.57

标签:10,money,抢红包,0.01,金额,算法,随机,100
From: https://www.cnblogs.com/phpphp/p/18004619

相关文章

  • 基础算法(九)二维前缀和模板---以题为例
    输入一个 n 行 m的整数矩阵,再输入q 个询问,每个询问包含四个整数 x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。对于每个询问输出子矩阵中所有数的和。输入格式第一行包含三个整数 n,m,q。接下来 n行,每行包含m 个整数,表示整数矩阵。接下来 q 行,每行包含四个......
  • 基础算法(八)前缀和模板---以前缀和题目为例
    题目如下输入一个长度为 n的整数序列。接下来再输入 m个询问,每个询问输入一对 l,r。对于每个询问,输出原序列中从第 l 个数到第 r个数的和。输入格式第一行包含两个整数 n 和 m。第二行包含 n 个整数,表示整数数列。接下来 m 行,每行包含两个整数 l 和 r,......
  • (坚持每天写算法)算法学习与复习part1基础算法1-13——位运算
    最近确实有在写算法,在写dp,之前学的时候不全,被计数,树型等dp折磨了一下。位运算是将重点放在数字的位上,通常作为辅助行动,比如状态dp,有的时候是为了节省时空复杂度而使用的。这是今天的题目: 位运算应用的情况除了上面讲的,还有单纯的位问题,上面的题目就是一个例......
  • 【优先级调度算法:抢占式与非抢占式】
    (文章目录)前言在操作系统中,进程调度决定了哪个进程应该获得CPU的使用权,以便能够执行。而优先级调度算法就是其中之一,它通过为每个进程分配一个优先级来决定进程的执行顺序。什么是优先级调度算法?优先级调度算法是一种用于确定哪个进程将在CPU上执行的方法。每个进程都会被分配......
  • 第十五节:排序算法详解3(希尔排序、计数排序、桶排序、基数排序)
    一.        二.        三.         !作       者:Yaopengfei(姚鹏飞)博客地址:http://www.cnblogs.com/yaopengfei/声     明1:如有错误,欢迎讨论,请勿谩骂^_^。声     明2:原创博客请在转载......
  • 伪随机数(gcd+裴蜀定理)
    第2题   伪随机数查看测评数据信息一个生成伪随机数的函数,seed(a+1)=[seed(a)+STEP]%MOD,为了能产生0~MOD-1的所有数,需要设定合适的STEP和MOD。例如,STEP=3,MOD=5,产生0,3,1,4,2,这是正确的设定;若STEP=15,MOD=20,只能产生0,15,10,5,这是错误的设定。 输入格式 ......
  • 算法学习
    今天学习了约数的个数怎么求,一般的算法会超时。这时我们需要用到一个定理:p=[n/i]:表示在[1,n]的区间内,有约数i的个数为p个。所以这时,在求约数个数的问题上,我们只需要遍历[1,n],设置一个计数器即可。当n很大时,跨越太大,这时i++、就会很慢,设置j=n/(n/i)+1;下一次让i=j;这样跨度较......
  • 基础模板/算法
    线性筛求素数#include<bits/stdc++.h>usingnamespacestd;constintN=5e7+50;intn,tot,prime[N];//prime存储所有素数boolflag[N];//判断是否为素数intmain(){scanf("%d",&n);//初始化,flag全部置为truefor(inti=1;i<=n;i++)fl......
  • Python数据结构与算法03-单循环链表
    单循环链表classListNode:def__init__(self,val,next=None):self.val=valself.next=nextclassSingleLoopLinkList:def__init__(self,node=None):self.__head=nodeifnode:#如果不是空链表node.next=node......
  • Python 机器学习 K-近邻算法 KD树
    在使用K-近邻(KNN)算法时,kd树(k-dimensionaltree)是一种用于减少计算距离次数从而提高搜索效率的数据结构。kd树是一种特殊的二叉树,用于存储k维空间中的数据点,使得搜索最近邻点更加高效。KD树的构造过程是将数据分割成更小的区域,直到每个区域满足特定的终止条件。1、构建KD树在k......