关于随机红包抽奖算法

场景:

  生成10个随机红包, 奖池总金额10000, 最小500, 最大1000,奖池全部分配完。

  分析:

  第一想法简单, 直接生成500-1000之间的随机数,直接生成10个, 直接上代码

   /**
     *
     * @param lst 生成的奖项列表
     * @param minAmount 红包允许的最小金额
     * @param maxAmount 红包允许的最大金额
     * @param totalAmount 总奖池金额
     * @param count 生成红包数量
     */public void generateRoundAmount(List<Integer> lst, Integer minAmount, Integer maxAmount, Integer totalAmount, Integer count){
        for (int i = 1; i <= count ; i++) {
            //当前理论允许的最大金额, 保证后续每人持有最小
            Integer tmpMax =  totalAmount - minAmount * (count - i);
            //前4成的最大金额,为理论最大金额的一半, 防止前面金额过大,后面全是1
            tmpMax = i <= Math.round(count*0.4) ? tmpMax/2 : tmpMax;
            //当有传入最大金额,且小于当前理论最大金额, 则取最大金额,否则取理论最大金额
            tmpMax = maxAmount != null && tmpMax > maxAmount ? maxAmount : tmpMax;
            //当最后一个的时候,全部归其所有, 否则取随机数区间[min, max]
            Integer tmpValue = i == count ? totalAmount : StringUtil.getRandomNumberBetween(minAmount, tmpMax);
            lst.add(tmpValue);
            //减去已抽取金额
            totalAmount = totalAmount - tmpValue;
        }
    }

  这种写法, 最后一个金额会出现问题,会有出现超过最大金额的可能性。

  解决方法有两种:

   第一种方法,判断最后一个金额大于maxAmount, 则重新运行,直到出现最后一个金额小于等于maxAmount即可。当然这种方法比较笨, 并不推荐。

   第二中方法,就是剩余的金额, 继续在已经生成的奖项列表中分配(未超过最大金额的项)。

  改造下方法

  

   /**
     *
     * @param lst 生成的奖项列表
     * @param minAmount 红包允许的最小金额
     * @param maxAmount 红包允许的最大金额
     * @param totalAmount 总奖池金额
     * @param count 生成红包数量
     */public void generateRoundAmount(List<Integer> lst, Integer minAmount, Integer maxAmount, Integer totalAmount, Integer count){
        Integer remainingAmount = 0; //剩余金额, 默认0
        for (int i = 1; i <= count ; i++) {
            //当前理论允许的最大金额, 保证后续每人持有最小
            Integer tmpMax =  totalAmount - minAmount * (count - i);
            //前4成的最大金额,为理论最大金额的一半, 防止前面金额过大,后面全是1
            tmpMax = i <= Math.round(count*0.4) ? tmpMax/2 : tmpMax;
            //当有传入最大金额,且小于当前理论最大金额, 则取最大金额,否则取理论最大金额
            tmpMax = maxAmount != null && tmpMax > maxAmount ? maxAmount : tmpMax;

            if(i == count && maxAmount != null && totalAmount > maxAmount){
                //最后一个红包数量大于最大允许金额, 计算出剩余金额
                lst.add(maxAmount);
                remainingAmount = totalAmount - maxAmount;
            } else{
                Integer tmpRandomInt = StringUtil.getRandomNumberBetween(minAmount, tmpMax);
                lst.add(tmpRandomInt);
                //奖池金额为总金额减去已抽取金额
                totalAmount = totalAmount - tmpRandomInt;
            }
        }
        //剩余金额大于0则继续分配
        while(remainingAmount > 0){
            addAmountToList(lst, maxAmount, remainingAmount);
        }
    }

    /**
     *
     * @param lst
     * @param maxAmount 允许最大金额
     * @param totalAmount 可分配金额
     */
    private void addAmountToList(List<Integer> lst, Integer maxAmount, Integer totalAmount){
        for (int i = 0; i < lst.size(); i++) {
            if (totalAmount <= 0){
                break;
            }
            if (lst.get(i) < maxAmount){ //当列表中的金额小于最大金额时, 才分配
                //临时最大允许金额
                Integer tmpMax = maxAmount - lst.get(i) > totalAmount ? totalAmount : maxAmount - lst.get(i);
                Integer tmpRandomInt = StringUtil.getRandomNumberBetween(1, tmpMax);
                lst.set(i, lst.get(i) + tmpRandomInt);
                totalAmount = totalAmount - tmpMax;
            }
        }
    }

  完工, 图方便, 金额直接用了Integer类型,可自行转换为decimal

原文地址:https://www.cnblogs.com/jolins/p/11536102.html

时间: 2024-11-10 09:20:09

关于随机红包抽奖算法的相关文章

随机红包生成算法-python实现

抢红包那么开心,那你知道红包随机算法是怎么样的吗? 我模拟写了一个定额随机红包生成算法,如下. 输入: 红包总额,total 份数,num 调控参数(调控红包最平均差,默认为2) 约束: 每份最少有1分钱,即0.01 份数需为正整数 红包总额 <= 份数×0.01 输出 随机红包序列,序列长度等于红包份数 运气王,即红包数额最大的一份 # -*- coding: cp936 -*- # 思路:先随机出来m个数,然后平均分成m个数字只和的份数,然后将钱平均分给m个人# import random

php 随机红包算法

/** * 红包分配算法 * * example * $coupon = new Coupon(200, 5); * $res = $coupon->handle(); * print_r($res); * @author Flc <2018-04-06 20:09:53> * @see http://flc.ren | http://flc.io | https://github.com/flc1125 */ class Coupon { /** * 红包金额 * @var float

抽奖算法-指定概率的随机

      抽奖算法       参考 Return random `list` item by its `weight`

微信红包生成算法 (解)

/** * 微信红包生成算法 * * @param int $total 红包金额 * @param int $num 拆分数量 * @param int $min 拆分的红包最小金额数目 */function set_packet($total, $num, $min = 0.01){ for ($i = 1; $i < $num; $i++) { //随机安全上限 $safe_total = ($total-($num-$i)*$min)/($num-$i); //红包金额 $money =

PHP用抛物线的模型实现微信红包生成算法的程序源码

<?php /* *Author:Kermit *Time:2015-8-26 *Note:红包生成随机算法 */ header("Content-type:text/html;charset=utf-8"); date_default_timezone_set('PRC'); #红包生成的算法程序 class reward { public $rewardMoney; #红包金额.单位元 public $rewardNum; #红包数量 public $scatter; #分散

PHP红包生成算法

一.适用场景 红包总金额X,分配成Y个红包,每个红包随机金额. 二.生成算法 /** * 红包生成算法 * @param $money 总金额 * @param $number 红包数量 * @param $ratio 浮动系数 */ function hongbao($money,$number,$ratio = 0.5){ $res = array(); //结果数组 $min = ($money / $number) * (1 - $ratio); //最小值 $max = ($money

java版根据权重抽奖算法

根据权重进行抽取的算法应用比较广泛,其中抽奖便是主要用途之一.正好这几天也正在进行抽奖模块的开发,整个抽奖模块涉及到的地方大概有三处,分别是后台进行奖品的添加(同时设置权重和数量),前台根据后台配置生成抽奖队列并根据指令开始抽奖活动,最后一部分是后台统计中奖情况并设置物流状态.本文主要针对前台抽奖算法进行介绍如何根据权重设置每个奖品被抽到的概率. 抽奖算法的核心是根据权重设置随机数出现的概率,在此我将它封装成一个生成随机数的随机类,代码如下: /** * JAVA 返回随机数,并根据概率.比率

随机快排算法

1 package Sort; 2 3 import org.junit.Test; 4 5 // 随机快排算法 6 public class RandQuickSort { 7 8 // 交换数组中的两个元素 9 public void exchange(int[] array, int index1, int index2) { 10 int tmp = array[index1]; 11 array[index1] = array[index2]; 12 array[index2] = t

中奖概率算法(php 可用于刮刮卡,大转盘等抽奖算法)

php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法.用法很简单,代码里有详细注释说明,一看就懂 <?php /* * 经典的概率算法, * $proArr是一个预先设置的数组, * 假设数组为:array(100,200,300,400), * 开始是从1,1000 这个概率范围内筛选第一个数是否在他的出现概率范围之内, * 如果不在,则将概率空间,也就是k的值减去刚刚的那个数字的概率空间, * 在本例当中就是减去100,也就是说第二个数是在1,900这个范围内筛选的. * 这样 筛选到最终,总