php 红包瓜分算法(实用)

php 红包瓜分算法

生成的红包总额等于发放的总额,

本源码解决了
生成的红包总额小于发放的总额或出现有负数金额以及0元的情况


例如:我发10元,20个红包,结果生成出来的数组金额之和等于了10元。
/**
*
*调用生成红包的方法
*
**/
 public function test()
    {
 $hongbao_arr=$this->getRedPackets($lottery_info['numerical'],$lottery_info['number']);
var_dump($hongbao_arr) 
}





/*
* *生成红包数组 * @param $total 红包总额 * @param $count 红包个数 * @param $bonus_max 每个小红包的最大额 * @param $bonus_min 每个小红包的最小额 * */ protected function getRedPackets($total = 0, $count = 0) { $yushu = ($total - intval($total)); //如果金额为小数则取出小数位 $bonus_total = ($total - $yushu) * 100; //如果金额为小数则去除小数小计算分配 $bonus_count = $count; $result = array(); if ($bonus_total / $bonus_count > 1) { if (($bonus_total - $bonus_total / 4) / ($bonus_count - 1) >= 1) { $bonus_max = $bonus_total / 4; if (($bonus_total / 4) == ($bonus_total / $bonus_count)) { $bonus_max += 50; } } else { for ($j = 0; $j < $count; $j++) { $result[$j] = ($bonus_total / $bonus_count) / 100; } $r = rand(0, $count - 1); $result[$r] = ($bonus_total - $bonus_count * 1 + 1) / 100; //如果还有负数产生就重新分配 $attr = array(); foreach ($result as $k => $v) { $attr[$k]['money'] = $v; // $attr[$k]['yili'] = 0; } return $attr; } } else { for ($k = 0; $k < $count; $k++) { $result[$k] = $total / $count / 100; } //如果还有负数产生就重新分配 $attr = array(); foreach ($result as $k => $v) { $attr[$k]['money'] = $v; // $attr[$k]['yili'] = 0; } return $attr; } $bonus_min = 1; $average = $bonus_total / $bonus_count; for ($i = 0; $i < $bonus_count; $i++) { //因为小红包的数量通常是要比大红包的数量要多的,因为这里的概率要调换过来。 //当随机数&gt;平均值,则产生小红包 //当随机数<平均值,则产生大红包 if (rand($bonus_min, $bonus_max) > $average) { // 在平均线上减钱 $temp = $bonus_min + $this-> xRandom($bonus_min, $average); $result[$i] = $temp; $bonus_total -= $temp; } else { // 在平均线上加钱 $temp = $bonus_max - $this-> xRandom($average, $bonus_max); $result[$i] = $temp; $bonus_total -= $temp; } } // 如果还有余钱,则尝试加到小红包里,如果加不进去,则尝试下一个。 while ($bonus_total > 0) { for ($i = 0; $i < $bonus_count; $i++) { if ($bonus_total > 0 && $result[$i] < $bonus_max) { $result[$i]++; $bonus_total--; } } } // 如果钱是负数了,还得从已生成的小红包中抽取回来 while ($bonus_total < 0) { for ($i = 0; $i < $bonus_count; $i++) { if ($bonus_total < 0 && $result[$i] > $bonus_min) { $result[$i]--; $bonus_total++; } } } //如果还有负数产生就重新分配 $attr = array(); //随机一个小红包加入金额小数位 $rands = rand(0, ($bonus_count - 1)); $result[$rands] += $yushu * 100; $nums = 0; //处理输出 foreach ($result as $k => $v) { if ($v < 1) { $this-> getBonus(); die; } $attr[$k]['money'] = $v / 100; $nums += $v; } return $attr; } /** * 生成min和max之间的随机数,但是概率不是平均的,从min到max方向概率逐渐加大。 * 先平方,然后产生一个平方值范围内的随机数,再开方,这样就产生了一种“膨胀”再“收缩”的效果。 */ protected function xRandom($bonus_min, $bonus_max) {   //求一个数的平方 $sqr = intval(($bonus_max - $bonus_min)*($bonus_max - $bonus_min)); $rand_num = rand(0, ($sqr - 1)); return intval(sqrt($rand_num)); }
原文地址:https://www.cnblogs.com/yuuje/p/14481434.html