当前位置:

实现红包算法(给定总金额 总人数 最大金额 最小金额)生成红包列表–PHP

温馨提示:本文共2043个字,读完预计6分钟。

描述:给定总积分,给定总人数,给定最大与最小值产生随机数
源代码:
    public function getBonus()
    {
        $total_point = 32000; //单位:分
        $total_people = 20;
        $point_max = 2000;  //单位:分
        $point_min = 1000;  //单位:分
        $bonus = $this->_getBonus($total_point, $total_people, $point_max, $point_min);

        return ajax_success('ok', $bonus);
    }

    /**
     * 功能:求一个数的平方
     * @param $n
     * @return float|int
     */
    public function _sqr($n)
    {
        return $n * $n;
    }

    /**
     * 功能:产生红包
     * @param $total_point
     * 红包总额
     * @param $total_people
     * 红包个数
     * @param $point_max
     * 每个小红包的最大额
     * @param $point_min
     * 每个小红包的最小额
     * @return array
     * 存放生成的每个小红包的值的一维数组
     */
    public function _getBonus($total_point, $total_people, $point_max, $point_min)
    {
        $result = array();
        $average = $total_point / $total_people;
        if ($point_max < $average) {
            for ($i = 0; $i < $total_people; $i++) {
                $result[$i] = $point_max;
            }
            return $result;
        }

        if ($point_min > $average) {
            for ($i = 0; $i < $total_people; $i++) {
                $result[$i] = $average;
            }
            return $result;
        }

        for ($i = 0; $i < $total_people; $i++) {
            //因为小红包的数量通常是要比大红包的数量要多的,因为这里的概率要调换过来。
            //当随机数>平均值,则产生小红包
            //当随机数<平均值,则产生大红包
            if (rand($point_min, $point_max) > $average) {
                //    在平均线上加积分
                $temp = $point_min + $this->_xRandom($point_min, $average);
                $result[$i] = $temp;
                $total_point -= $temp;
            } else {
                //    在平均线上减钱
                $temp = $point_max - $this->_xRandom($average, $point_max);
                $result[$i] = $temp;
                $total_point -= $temp;
            }
        }
        //        如果还有余积分,则尝试加到小红包里,如果加不进去,则尝试下一个。
        while ($total_point > 0) {
            for ($i = 0; $i < $total_people; $i++) {
                if ($total_point > 0 && $result[$i] < $point_max) {
                    $result[$i]++;
                    $total_point--;
                }
            }
        }
        //如果积分是负数了,还得从已生成的大于最小红包的红包中抽取回来
        while ($total_point < 0) {
            for ($i = 0; $i < $total_people; $i++) {
                if ($total_point < 0 && $result[$i] > $point_min) {
                    $result[$i]--;
                    $total_point++;
                }
            }
        }
        return $result;
    }

    /**
     * 功能:生产 min 和 max 之间的随机数,但是概率不是平均的,从 min  到 max 方向概率逐渐减小。
     * 先平方,然后产生一个平方值范围内的随机数,再开方,这样就产生了一种 膨胀 再 收缩 的效果。
     * @param $point_max
     * 每个小红包的最大额
     * @param $point_min
     * 每个小红包的最小额
     * @return int
     */
    public function _xRandom($point_min, $point_max)
    {
        $sqr = intval($this->_sqr($point_max - $point_min));
        $rand_num = rand(0, ($sqr - 1));
        return intval(sqrt($rand_num));
    }

返回示例:返回的数据单位也是分。
{
    "code": 200,
    "msg": "ok",
    "content": [
        1652,
        1556,
        1853,
        1814,
        1784,
        1572,
        1819,
        1051,
        1850,
        1519,
        1317,
        1752,
        1579,
        1557,
        1417,
        1602,
        1694,
        1427,
        1542,
        1643
    ]
}
本文链接:,转发请注明来源!
评论已关闭。