发一个随机红包,100块给10个人,每个人最多12块,最少6块

lianrouwupan 2016-09-09 10:02:57
发一个随机红包,100块给10个人,每个人最多12块,最少6块
最大的红包和最小的红包只能出现一次。
求代码如何修改

function redEnvelope(){
$n = 10;
$sum = 100;
$result = array();
while($n > 1){
$randNum = mt_rand(6,12);
if(($sum-$randNum) >= 6*($n-1) && ($sum-$randNum) <= 12*($n-1)){
$sum -= $randNum;
$n -= 1;
$result[] = $randNum;
}

}
$result[] = $sum;
return $result;
}
...全文
516 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
lianrouwupan 2016-09-10
  • 打赏
  • 举报
回复
感谢大神们的回复,我先结贴吧。要看懂这些代码不是一时半刻的事。
晓之海绵宝宝 2016-09-09
  • 打赏
  • 举报
回复
能否解释一下if(($sum-$randNum) >= 6*($n-1) && ($sum-$randNum) <= 12*($n-1)) 这个条件是何用意?
lianrouwupan 2016-09-09
  • 打赏
  • 举报
回复

	function redEnvelope(){
		$n = 10;
		$sum = 100;
		$result = array();
		$sixEnvelope = 0;
		$twelveEnvelope = 0;
		while($n > 1){
			$randNum = mt_rand(6,12);
			if($randNum == 6){
				++$sixEnvelope;
			}
			if($randNum == 12){
				++$twelveEnvelope;
			}

			if($sixEnvelope > 1){
				$sixEnvelope = 1;
				continue;			
			}else if($twelveEnvelope > 1){
				$twelveEnvelope = 1;
				continue;			
			}else{
				if(($sum-$randNum) >= 6*($n-1) && ($sum-$randNum) <= 12*($n-1)){
					$sum -= $randNum;
					$n -= 1;
					$result[] = $randNum;
				}
			}
		}
		$result[] = $sum;
		return $result;
	}
请教各位,我这样写会死循环,逻辑哪里错了?
超人不会飞呐 2016-09-09
  • 打赏
  • 举报
回复
while($n > 1)前加 $a=0;$b=0; $randNum = mt_rand(6,12);后加 if($randNum ==6){ $a=1; }else if($randNum ==12){ $b=1; } if($a==1){ $randNum=$randNum+mt_rand(0,5); }else if($b==1){ $randNum=$randNum-mt_rand(0,5); } 随便想的,不知道对不对,肯定还有更好的方法。
笨狗先飞 2016-09-09
  • 打赏
  • 举报
回复

####函数实现部分####
function redEnvelope()
{
  $result=array(1000,1000,1000,1000,1000,1000,1000,1000,1000,1000);
  while(1)
  {
    $id=mt_rand(0,9);
    $v=mt_rand(0,$result[$id]-600);
    $result[$id]-=$v;
    $result[mt_rand(0,9)]+=$v;
    $min=1300;
    $max=500;
    for($i=0;$i<10;$i++)
    {
      if($result[$i]==$max)break;
      if($result[$i]==$min)break;
      if($result[$i]>1200)break;
      if($result[$i]<600)break;
      if($result[$i]>$max)$max=$result[$i];
      if($result[$i]<$min)$min=$result[$i];
    }
    if($i==10)break;
  }
  return $result;
}
####验证显示部分###########################
$v=redEnvelope();
$min=1300;
$max=500;
$sum=0;
for($i=0;$i<10;$i++)
{
  if($v[$i]>$max)$max=$v[$i];
  if($v[$i]<$min)$min=$v[$i];
  $sum+=$v[$i];
  echo('['.($i+1).']='.($v[$i]/100).'<br>');
}
echo 'max='.($max/100).'<br>';
echo 'min='.($min/100).'<br>';
echo 'sum='.($sum/100).'<br>';
傲雪星枫 2016-09-09
  • 打赏
  • 举报
回复

/**
* 求一个数的平方
* @param $n
*/
function sqr($n){
return $n*$n;
}
/**
* 生产min和max之间的随机数,但是概率不是平均的,从min到max方向概率逐渐加大。
* 先平方,然后产生一个平方值范围内的随机数,再开方,这样就产生了一种“膨胀”再“收缩”的效果。
*/
function xRandom($bonus_min,$bonus_max){
$sqr = intval(sqr($bonus_max-$bonus_min));
$rand_num = rand(0, ($sqr-1));
return intval(sqrt($rand_num));
}
/**
*
* @param $bonus_total 红包总额
* @param $bonus_count 红包个数
* @param $bonus_max 每个小红包的最大额
* @param $bonus_min 每个小红包的最小额
* @return 存放生成的每个小红包的值的一维数组
*/
function getBonus($bonus_total, $bonus_count, $bonus_max, $bonus_min) {
$result = array();
$average = $bonus_total / $bonus_count;
$a = $average - $bonus_min;
$b = $bonus_max - $bonus_min;
//
//这样的随机数的概率实际改变了,产生大数的可能性要比产生小数的概率要小。
//这样就实现了大部分红包的值在平均数附近。大红包和小红包比较少。
$range1 = sqr($average - $bonus_min);
$range2 = sqr($bonus_max - $average);
for ($i = 0; $i < $bonus_count; $i++) {
//因为小红包的数量通常是要比大红包的数量要多的,因为这里的概率要调换过来。
//当随机数>平均值,则产生小红包
//当随机数<平均值,则产生大红包
if (rand($bonus_min, $bonus_max) > $average) {
// 在平均线上减钱
$temp = $bonus_min + xRandom($bonus_min, $average);
$result[$i] = $temp;
$bonus_total -= $temp;
} else {
// 在平均线上加钱
$temp = $bonus_max - 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++;
}
}
}
return $result;
}
$bonus_total = 100;
$bonus_count = 10;
$bonus_max = 12;//此算法要求设置的最大值要大于平均值
$bonus_min = 6;
$result_bonus = getBonus($bonus_total, $bonus_count, $bonus_max, $bonus_min);
$total_money = 0;
$arr = array();
foreach ($result_bonus as $key => $value) {
$total_money += $value;
if(isset($arr[$value])){
$arr[$value] += 1;
}else{
$arr[$value] = 1;
}
}
//输出总钱数,查看是否与设置的总数相同
echo $total_money;
//输出所有随机红包值
var_dump($result_bonus);
//统计每个钱数的红包数量,检查是否接近正态分布
ksort($arr);
var_dump($arr);
xuzuning 2016-09-09
  • 打赏
  • 举报
回复
$result = array_fill(0, $num, $min); //将最小值分配给每个人 $loop = $sum - $num * $min; //剩余的数量 $i = 0; while($loop) { $randNum = mt_rand(1, min($loop, $max - $min)); //随机取一个数 if($randNum && $result[$i] + $randNum <= $max) { //如果分配给某人能成功 $result[$i] += $randNum; //那就分配 $loop -= $randNum; //总而当然也要减少 } $i = ($i + 1) % $num; } //分配结束
lianrouwupan 2016-09-09
  • 打赏
  • 举报
回复
引用 4 楼 xuzuning 的回复:
$r = redEnvelope(100, 10, 12, 6);
echo array_sum($r); //校验结果
print_r($r); //查看分布

function redEnvelope($sum, $num, $max, $min){
  $result = array_fill(0, $num, $min);
  $loop = $sum - $num * $min;
  $i = 0;
  while($loop) {
    $randNum = mt_rand(1, min($loop, $max - $min));
    if($randNum && $result[$i] + $randNum <= $max) {
      $result[$i] += $randNum;
      $loop -= $randNum;
    }
    $i = ($i + 1) % $num;
  } //分配结束
  //$max 至多出现一次
  $m = array_keys($result, max($result));
  if(count($m) > 1 && $result[$m[0]] == $max) {
    for($i=1; $i<count($m); $i++) {
      $n = array_keys($result, min($result));
      $result[$m[$i]]--;
      $result[$n[0]]++;
    }
  }
  //$min 至多出现一次
  $m = array_keys($result, min($result));
  if(count($m) > 1 && $result[$m[0]] == $min) {
    for($i=1; $i<count($m); $i++) {
      $n = array_keys($result, $min + 2);
      $result[$m[$i]]++;
      $result[$n[0]]--;
    }
  }
  return $result;
}
能否解释一下代码?
xuzuning 2016-09-09
  • 打赏
  • 举报
回复
或者干脆强制最大和最小个出现一次
$r = redEnvelope(100, 10, 12, 6);
echo array_sum($r);
print_r($r);

function redEnvelope($sum, $num, $max, $min) {
  $result = array_fill(0, $num - 2, $min + 1);
  $loop = $sum - ($num - 2) * ($min + 1) - $max - $min;
  $i = 0;
  while($loop) {
    $randNum = mt_rand(1, min($loop, $max - $min - 2));
    if($randNum && $result[$i] + $randNum < $max) {
      $result[$i] += $randNum;
      $loop -= $randNum;
    }
    $i = ($i + 1) % ($num - 2);
  } //分配结束
  $result[] = $max;
  $result[] = $min;
  return $result;
}
xuzuning 2016-09-09
  • 打赏
  • 举报
回复
$r = redEnvelope(100, 10, 12, 6);
echo array_sum($r); //校验结果
print_r($r); //查看分布

function redEnvelope($sum, $num, $max, $min){
$result = array_fill(0, $num, $min);
$loop = $sum - $num * $min;
$i = 0;
while($loop) {
$randNum = mt_rand(1, min($loop, $max - $min));
if($randNum && $result[$i] + $randNum <= $max) {
$result[$i] += $randNum;
$loop -= $randNum;
}
$i = ($i + 1) % $num;
} //分配结束
//$max 至多出现一次
$m = array_keys($result, max($result));
if(count($m) > 1 && $result[$m[0]] == $max) {
for($i=1; $i<count($m); $i++) {
$n = array_keys($result, min($result));
$result[$m[$i]]--;
$result[$n[0]]++;
}
}
//$min 至多出现一次
$m = array_keys($result, min($result));
if(count($m) > 1 && $result[$m[0]] == $min) {
for($i=1; $i<count($m); $i++) {
$n = array_keys($result, $min + 2);
$result[$m[$i]]++;
$result[$n[0]]--;
}
}
return $result;
}

21,886

社区成员

发帖
与我相关
我的任务
社区描述
从PHP安装配置,PHP入门,PHP基础到PHP应用
社区管理员
  • 基础编程社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧