# 算法面试问题：发一个随机红包，100块钱给10个人。每个人最多12块钱，最少6块钱。怎么分？

xinhaip
• 309

36 个回答

• 1.1k
✓ 已被采纳
``````\$cash = 40;
\$user_arr = array(6,6,6,6,6,6,6,6,6,6);
while(\$cash>0){
\$user_id = rand(0, 9);
if(\$user_arr[\$user_id]<12){
\$user_arr[\$user_id]++;
\$cash--;
}
}

;
var_dump(\$user_arr,array_sum(\$user_arr));die;``````
``````性能篇
\$arr1=range(2,6);
shuffle(\$arr1);
\$arr2=range(2,6);
shuffle(\$arr2);
\$user_arr = array(6,6,6,6,6,6,6,6,6,6);
for (\$i=0;\$i<10;\$i++){

if(\$i<=4){
\$user_arr[\$i] += \$arr1[\$i];
}else{
\$j = \$i%5;
\$user_arr[\$i] += \$arr2[\$j];

}
}
var_dump(\$user_arr,array_sum(\$user_arr));die;``````
dawniii
• 417
``````<?php
//总钱数
\$allMoney = 100;
//人数
\$peopleNum = 10;
//红包结果
\$result = [];
//随机生成10个红包
for (\$i=0;\$i<\$peopleNum;\$i++){
\$result[\$i] = mt_rand(6,12);
}
//取结果总钱数差
\$diff = array_sum(\$result) - \$allMoney;
\$absDiff = abs(\$diff);
//多退少补
for(\$i=0;\$i<\$absDiff;\$i++) {
foreach (\$result as \$key => \$value) {
if (\$diff > 0) {
\$value--;
if (\$value >= 6) {
\$result[\$key] = \$value;
break;
}
} elseif (\$diff < 0) {
\$value++;
if (\$value <= 12) {
\$result[\$key] = \$value;
break;
}
} else {
break 2;
}
}
}

//输出红包结果
var_dump(\$result);
//输出红包总钱数
var_dump(array_sum(\$result));``````

``````<?php
function makePaper()
{
\$result = [];
for (\$i=0;\$i<10;\$i++){
\$result[\$i] = mt_rand(6,12);
}

if (array_sum(\$result) != 100) {
return makePaper();
}

return \$result;
}``````

``````<?php

function makePaper(\$allMoney = 100, \$peopleNum = 10, \$min = 6, \$max = 12)
{
\$result = [];
for (\$i=0;\$i<10;\$i++){
\$result[\$i] = mt_rand(\$min*100,\$max*100);
}

if (array_sum(\$result) != \$allMoney*100) {
return makePaper();
}

return array_map(function(\$money){
return bcdiv(\$money,100,2);
},\$result);
}

\$result = makePaper();
var_dump(\$result);
var_dump(array_sum(\$result));``````

• 223

``````<?php

function hongbao(\$money, \$people, \$min, \$max)
{
\$result = [];
for (\$i=0; \$i < \$people; \$i++) {
do {
// 1.进行本次分配
\$result[\$i] = mt_rand(\$min*100, \$max*100) / 100;
// 2.本次分配后，剩余人数
\$restPeople = \$people - (\$i+1);
// 3.本次分配后，剩余金钱
\$restMoney  = \$money - array_sum(array_slice(\$result, 0, \$i+1));
// 4.本次分配后，剩余金钱是否在合理范围？ 不在则重新分配
} while (\$restMoney > \$restPeople * \$max || \$restMoney < \$restPeople * \$min);
}
return \$result;
}

\$result = hongbao(100, 10, 6, 12);
// 验证
var_dump(\$result);
var_dump(array_sum(\$result));``````

Booker
• 423

X为已经抽取的数值
Y为已经抽取的人数

1.剩余金额除以人数不能大于12
2.剩余金额除以人数不能小于6
3.每个人都只能在6~12里选
4.总金额100分为10个人

m为总金额,n为人数，min选择下限，max为选择上限,用方程式

（我的代码写得很不pythonic请不要吐槽，位数采用默认的很多位小数，根据实际情况再进行削减）

``````#encoding=utf8

from random import uniform

def flag(m, n, min, max):
x = 0
y = 0
L = []
for i in range(n):
top = 12
bottom = 6
if not m-x-min*(n-y-1) >= 12:
top = m-x-min*(n-y-1)
if not m-x-max*(n-y-1) <= 6:
bottom = m-x-max*(n-y-1)
next = uniform(bottom, top)
x += next
y += 1
L.append(next)
return L

print flag(100, 10, 6, 12)
print sum(flag(100, 10, 6, 12))

``````

=================

PS：看到题主的评论，题主的思路有人提到是随机到6块这种的概率很低，假如真的如此（偷懒没试过），那算法直觉就是集中化趋势的过程了。没有好坏，只是看需求如何。

liuxc2016
• 229

``````
//rem，当前递归层次还有多少个数没有生成，\$total生成总量，在这个项目中为40，\$must必须达到的数据,\$arr，临时变量用来保存和传递用
//返回类型,\$arr,即生成的随机数组
function test(\$rem, \$total, \$must, \$arr)
{
if(\$rem>=2)
{
\$rem -= 1;
//\$min本轮生成随机数的最小值是多少
\$min = round(\$must - \$rem * 6 , 2);
if(\$min<=0)
\$min =0;
\$max = (\$must > 6) ? 6 : \$must;
\$rand = round(mt_rand(\$min*100, \$max*100)/100 , 2);
\$arr[] = \$rand;
\$must = \$must - \$rand;
echo "生成rand数值:".\$rand;
echo "--剩余随机次数:".\$rem."----必须达成数据:".\$must;
echo "<br>";
return test(\$rem, \$total, \$must, \$arr);
}else{
\$arr[] = \$must;
return \$arr;
}

}
\$arr = array();
\$brr = test(10, 40, 40,\$arr);
//以后如果我想得到5个人分20块钱，也可以直接调用
//test(5,20,20,\$arr)即可
print_r(\$brr);
``````

``````生成rand数值:0.41--剩余随机次数:9----必须达成数据:39.59

Array ( [0] => 0.41 [1] => 0.81 [2] => 5.72 [3] => 2.51
[4] => 1.25 [5] => 5.34 [6] => 5.98 [7] => 5.99 [8] => 6 [9] => 5.99 )``````
cppprimer
• 180

``````function makeSeq(){
\$n = 10;
\$sum = 100;
\$result = [];
while (\$n > 1) {
// 6n <= sum <=12n
\$randNum = mt_rand(600,1200) / 100;
if((\$sum-\$randNum) >= 6* (\$n - 1) && (\$sum-\$randNum) <= 12* (\$n - 1)){
\$sum -= \$randNum;
\$n -= 1;
\$result[] = \$randNum;
}
}
\$result[] = \$sum;
return \$result;
}

print_r(makeSeq());
print_r(array_sum(makeSeq()));``````

7.20更新高新能版

``````function makeSeq2(){
\$n = 10;
\$sum = 100;
\$result = [];
for(\$i=\$n;\$i>=1;\$i--){
\$min = (\$sum - 12 * (\$i-1))>6?(\$sum - 12 * (\$i-1)):6;
\$max = (\$sum - 6 * (\$i-1))<12?(\$sum - 6 * (\$i-1)):12;
\$randNum = mt_rand(\$min,\$max);
\$sum -= \$randNum;
\$result[] = \$randNum;
}
return \$result;
}``````

thxyh99
• 22
``````function microtime_float(){
list(\$usec, \$sec) = explode(" ", microtime());
return ((float)\$usec + (float)\$sec);
}

function getRandParcent(){
return rand(1,10)/rand(10,100);
}

function randUserMoney(\$cash,\$min=6,\$max=12){
\$cash_ini = \$cash;
\$user_arr = array(\$min,\$min,\$min,\$min,\$min,\$min,\$min,\$min,\$min,\$min);
\$start = microtime_float();
while(\$cash>0){
\$user_id = rand(0, 9);
\$rand_point = getRandParcent();
if(\$user_arr[\$user_id]<\$max){
\$ing = microtime_float();
if(\$ing-\$start>0.01){
return randUserMoney(\$cash_ini);
}
\$rand_money = round(\$rand_point*\$cash,2);
\$user_money = \$user_arr[\$user_id]+\$rand_money ;
if(\$user_money<\$max){
\$user_arr[\$user_id] = \$user_money;
\$cash = \$cash - \$rand_money;
}
}
}
return [
'user_money'=>\$user_arr,
'total_money'=>array_sum(\$user_arr),
'excute_time'=>\$ing-\$start
];
}

var_dump(randUserMoney(40));

array (size=3)
'user_money' =>
array (size=10)
0 => float 11.59
1 => float 9.07
2 => float 11.99
3 => float 12
4 => float 9.14
5 => float 11.6
6 => float 11.86
7 => float 9.93
8 => float 6
9 => float 6.82
'total_money' => float 100
'excute_time' => float 0.004000186920166``````
renshan
• 34

``````<?php

\$money  = 40;
\$people = array_fill(0, 10, 6);

do {

\$lucky_index = mt_rand(0, 9);
\$lucky_money = floatval(substr(mt_rand() / mt_getrandmax(), 0, 4));

if(\$people[\$lucky_index]+\$lucky_money >= 12)
continue;

if(\$money < 1) {
\$m = \$money;
} else {
\$m = \$lucky_money;
}

\$people[\$lucky_index] += \$m;
\$money -= \$m;

} while(\$money > 0);

print_r(\$people);

?>``````

1.先每人分6元，还剩下40元。
2.起一个循环，每人分0-（12-他已有的钱）元随机，直到钱分完为止。

``````\$arr = [];
for (\$i=0; \$i < 9; \$i++) {
\$arr[] = mt_rand(6,12);
}
array_push(\$arr, 100 - array_sum(\$arr));
var_dump(\$arr);
var_dump(array_sum(\$arr));``````

ospheric
• 1
`````` <?php
// 1.初始化，平均分配每人\$initAvgMoney（根据限制条件随机产生）
// 2.每人随机拿出一定金额到共享资金池中，进行重新分配
// 限制条件：\$initAvgMoney应满足条件："小宝"一分钱也不放入共享资金池（"特自私"），其余九人拿出尽可能多的钱到共享资金池（每人只留6元）的情况下，共享资金池平均分配后小宝的钱也不超过12块

\$minInitAvgMoney = 600;
// (\$maxInitAvgMoney - 600) * 9 / 10 + \$maxInitAvgMoney <= 1200;
\$maxInitAvgMoney = floor(1740 / 1.9);
echo("maxInitAvgMoney:");var_dump(\$maxInitAvgMoney);

\$initAvgMoney = mt_rand(\$minInitAvgMoney, \$maxInitAvgMoney) ;
echo("initAvgMoney:");var_dump(\$initAvgMoney);

\$maxMinus = \$initAvgMoney - 600;
echo("maxMinus:");var_dump(\$maxMinus);

\$moneyArr = array();
for(\$i = 0; \$i < 10; \$i ++){
\$randMinusArr[\$i] = mt_rand(0, \$maxMinus / 10) * 10;
// echo("randMinusArr-{\$i}");var_dump(\$randMinusArr[\$i]);
\$moneyArr[\$i] = \$initAvgMoney - \$randMinusArr[\$i];
}

\$randMinusSum = 10000 - \$initAvgMoney * 10 + array_sum(\$randMinusArr);

for(\$i = 0; \$i < 10; \$i ++){
\$moneyArr[\$i] = (\$moneyArr[\$i] + \$avgAddMoney) / 100;
}

echo "最终结果：";var_dump(\$moneyArr);
echo "结果验证：";var_dump(array_sum(\$moneyArr));
// 感觉还有可以完善的地方，先这样吧
``````
wally7
• 17
``````min ＝ 6；
max ＝ 12；
total ＝ 100；
pe = 10;
maxTotal = max*pe － total;

list ＝ array()；
for （0<pe）
if(maxTotal>0)
temp = random(0,maxTotal>=6?6:maxTotal);
maxTotal-=temp;
list.push(12-temp);

if(maxTotal>0)
pre = maxTotal/pe;
for （0<pe）list［temp2］+＝pre；

shuffle(list);
``````

hsinchu
• 18

1.先将人分为两半，左半人分的总金额最少是左半人数x最少金额总金额-右半人数x最多金额两个数字中较大的；
2.左半人分的总金额最多是左半人数x最多金额总金额-右半人数x最少金额两个数字中较小的；
3.在这个范围内取随机数作为分给左半人的金额，然后将问题递归为左半人分钱和右半人分钱。
py代码（直接以分为单位，数字都是整数）：

``````import random

def deliver(sum_of_money,num_of_people,min_of_money,max_of_money):
if num_of_people==1:
arr = [sum_of_money]
return arr
else:
half = num_of_people>>1
border_left = max(min_of_money*half,(sum_of_money-(num_of_people-half)*max_of_money))
border_right = min(max_of_money*half,(sum_of_money-(num_of_people-half)*min_of_money))
sum_of_left = random.randint(border_left,border_right)
arr_left = deliver(sum_of_left,half,min_of_money,max_of_money)
arr_right = deliver(sum_of_money-sum_of_left,num_of_people-half,min_of_money,max_of_money)
return arr_left+arr_right

list = deliver(10000,10,600,1200)
print list``````

``````function faHongBao(money, pe, min, max) {
var sum = money,
result = [];

for(var i=0; i<pe; i++) {
result.push(min);
sum -= min;
}

while(sum > 0) {
var ran = Math.floor( Math.random() * (pe - 1) );
if(result[ran] < max) {
result[ran]++;
sum--;
}
}

return result;
}``````

Lozye
• 3
``````
static void Main(string[] args)
{
int all = 100;//总金额
int person = 10;//人数
double min = 8;//最小金额
double max = 12;//最大金额

double[] array = new double[person];//分配结果集
int i = 0;//第几人
Random ran = new Random();

//默认分配最小值
for (i = 0; i < person; i++)
{
array[i] = min;
}

double yet = min * person;//已分配金额

int whileTimes = 0;//记录循环次数
while (yet < all)
{
double thisM = Math.Round((ran.NextDouble() * (max - min - 1)), 2);
i = ran.Next(0, person);
if (yet + thisM > all)
{
thisM = all - yet;
}

if (array[i] + thisM < max)//判断是否超出最大金额
{
array[i] += thisM;
yet += thisM;
}
whileTimes++;
}

Console.Write("共循环{0}次\r\n", person + whileTimes);
yet = 0;
for (i = 0; i < person; i++)
{
yet += array[i];
Console.Write("第{0}人=>分配{1}元，合计分配{2}元\r\n", i + 1, array[i], yet);
}

}
``````
lovegamenoob
• 1
``````function roundmoney()
{
\$cash=100;

for (\$i = 0; \$i < 10; \$i++) {
\$people[\$i]=rand(6,12);
\$cash=\$cash-\$people[\$i];
if(\$cash==0&&\$i==9)
{
return \$people;
}
}
return false;

}
while(true)
{
if((\$res=roundmoney())!=false)
{
var_dump(\$res);
break;
}

}``````

• 2

zjruan
• 3

1、总数是100；
2、10个人分；
3、最小6块；
4、最大12块；
5、红包分完（例如都是6块的情况不存在）。

① restNum * range <= restPool : 每个人得到最大奖金依然没有(刚好)分配完奖金：retrun range；
② (restNum-1) * range > restPool : 判断下一次剩余人员能否分配完奖金池，如果能，则本次随机区间在[0,range]
③ restNum range > restPool > (restNum-1) range : 不能，则随机区间在[restPool % range,range]

``````function demo(total, min, max, num){
var pool = total - min * num;
var restNum = num ; // 剩余人数
var restPool = pool; // 剩余奖金

var minSignal = function(){
var range = max - min; // 最大奖金
return restNum * range > restPool ? (restNum-1) * range > restPool ? 0 : restPool % range : range ;
};

var dispatch = function (){
var minS = minSignal();
var temp = minS + Math.random() * ( max - min - minS);
temp = temp > restPool ? restPool : temp;
restPool -= temp;
return min + temp;
}

for(var i = 0; i < num; i++){
var prize = dispatch();
restNum --;
console.log("第"+ (i+1) +"个人：" + prize ,"剩余奖金池：" + restPool);
}
}

// 测试
demo(100, 6 , 12, 10)
2016-07-20 12:57:29.056 VM9998:19 第1个人：8.917007956230712 剩余奖金池：37.08299204376929
2016-07-20 12:57:29.056 VM9998:19 第2个人：11.711160108665778 剩余奖金池：31.371831935103508
2016-07-20 12:57:29.056 VM9998:19 第3个人：9.60431933144148 剩余奖金池：27.767512603662027
2016-07-20 12:57:29.057 VM9998:19 第4个人：9.005495062706432 剩余奖金池：24.762017540955597
2016-07-20 12:57:29.057 VM9998:19 第5个人：6.881776388287364 剩余奖金池：23.880241152668233
2016-07-20 12:57:29.057 VM9998:19 第6个人：11.477396582224884 剩余奖金池：18.40284457044335
2016-07-20 12:57:29.057 VM9998:19 第7个人：11.980543481582266 剩余奖金池：12.422301088861083
2016-07-20 12:57:29.057 VM9998:19 第8个人：10.577151778799255 剩余奖金池：7.845149310061829
2016-07-20 12:57:29.057 VM9998:19 第9个人：10.915993913333269 剩余奖金池：2.92915539672856
2016-07-20 12:57:29.057 VM9998:19 第10个人：8.92915539672856 剩余奖金池：0``````
hanbo2854
• 1

100元，给10人；范围6-12元
1，每人先发6元。 剩下每人最多还能分到6元。 剩下40元
2，如果按照整元分； 那么等价于40元分到60个槽。。。
3，如果要精确到分， 那么等价于40 00 分 分到 60 * 100个槽。。。

• 2

``````import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class RandomMoney {
public static void main(String[] args) {
int len = 10;
float allMoney = 100;//总钱数
float remainMoeny = 0;//剩余得钱数
float randomMoney = 0;//随机生成得钱数![图片描述][1]
float sumMoney = 0;//每次随机生产钱数得总和
int index; //随机索引
float oneMoney;//某一次随机得钱数
List<Object> list = new ArrayList<Object>();
Random  random = new Random();
for (int i = 0; i < len; i++) {
}
sumMoney = sumMoney(list ,len);
Long star = System.nanoTime();//System.currentTimeMillis();
while ((remainMoeny = allMoney - sumMoney) > 0) {
//产生一个剩余钱下的随机数
index = random.nextInt(10);
//当剩余得钱数少于一角 就把剩下得随机给某一个
if (remainMoeny < 1f&&remainMoeny > 0) {
//某一个人的钱数
oneMoney = (float)list.get(index)+(allMoney-sumMoney);
if (oneMoney < 12f) {
list.set(index, oneMoney);
sumMoney = sumMoney(list, len);
System.out.println(list);
System.out.println(sumMoney);
}
}else {
//随机生产得钱数
randomMoney = random.nextInt((int)remainMoeny)+random.nextFloat();
//某一个人得钱数
oneMoney = (float)list.get(index)+randomMoney;
if (oneMoney < 12f) {
list.set(index, oneMoney);
sumMoney = sumMoney(list , len);
}
}
}
long end = System.nanoTime();//System.currentTimeMillis();
System.out.println(end-star);
}
public static float sumMoney(List<Object> list ,int len){
float sumMoney = 0;
for (int i = 0; i < len; i++) {
sumMoney += (float)list.get(i);
}
return sumMoney;
}
}``````

zhangsan
• 599
``````function fhb(\$money,\$num,\$min,\$max){
\$firstUse=\$num*\$min;
\$surplusMoney=\$money-\$firstUse;

\$arr=array();
for(\$i=1;\$i<=\$num;\$i++){
\$arr[]=\$min;
}

\$diff=\$surplusMoney*100;
while(\$diff>0){
\$randUid = rand(0, \$num - 1);
if(\$arr[\$randUid]<\$max){
\$arr[\$randUid]+=0.01;
\$arr[\$randUid]=number_format(\$arr[\$randUid],2,'.','');
\$diff--;
}
}
return \$arr;
}

\$a=fhb(100,10,6,12);``````

``````Array
(
[0] => 9.75
[1] => 9.84
[2] => 10.06
[3] => 10.15
[4] => 9.94
[5] => 10.17
[6] => 10.00
[7] => 10.24
[8] => 9.86
[9] => 9.99
)``````
wchao
• 16

<?php

``````function hongbao(\$money, \$people, \$min, \$max) {
if(\$people * \$min > \$money || \$people * \$max < \$money) {
return false;
}
\$result = [];
for(\$i = 0;\$i < \$people; ++\$i) {
if(\$i == \$people - 1) {
\$result[\$i] = \$money - array_sum(\$result);
break;
}
\$rand = mt_rand(\$min * 100, \$max * 100)/100;
while(!isset(\$result[\$i])) {
\$restMoney = \$money - array_sum(\$result) - \$rand;
if(\$restMoney > (\$people - \$i -1) * \$max) {
\$rand += 1;
\$rand > \$max && \$rand = \$max;
} elseif(\$restMoney < (\$people - \$i - 1) * \$min) {
\$rand -= 1;
} else {
\$result[\$i] = \$rand;
}
}
}
return \$result;
}

\$result = hongbao(100, 10, 6, 12);
print_r(\$result);
print_r(array_sum(\$result));``````

?>

LenSun
• 1
``````<?php
function randMoney(\$totalMoney, \$people, \$max, \$min)
{
if (\$max * \$people < \$totalMoney || \$min * \$people > \$totalMoney) {
throw new Exception("总金钱不可以大于最大值与人数的乘积,不可以小于最小值与人数的乘积", 1);
return [];
}

\$minRest   = round((\$people * \$max - \$totalMoney) / (\$people - 1), 2) + 0.01;
\$restMoney = \$totalMoney;
\$result    = [];
\$time      = 0;
while (\$restMoney) {
for (\$i = 0; \$i < \$people; \$i++) {
\$time++;
if (\$restMoney > 0) {
if (\$restMoney <= \$min) {
\$currenRand = \$restMoney;
} else {
\$currenRand = \$max - \$min;
}
if (\$restMoney <= \$minRest) {
\$rand = \$restMoney;
} else {
\$rand = mt_rand(0.00, \$currenRand * 100) / 100;
}
if (isset(\$result[\$i])) {
if (\$result[\$i] + \$rand <= \$max) {
\$result[\$i] += \$rand;
\$restMoney -= \$rand;
}
} else {
\$result[\$i] = \$min + \$rand;
\$restMoney -= \$result[\$i];
}
if (!\$restMoney) {
break;
}
}
}
}
return \$result;
}

try {
\$result = randMoney(100, 10, 12, 6);
var_dump(\$result);
echo array_sum(\$result);
} catch (Exception \$e) {
echo \$e->getMessage();
}``````

X+10Y = 100;
X+Y<=12;

（借鉴了上一位回答者的回答）

citaret
• 862

s-x：[(n-1)a, (n-1)b] ==> x: [s-(n-1)a, s-(n-1)b],

php 没用过，用python的生成器可以简单的实现：

``````import random

def hongbao(s, n, a, b):
for i in range(n-1, -1, -1):
x = random.randint(max(a, s-b*i), min(b, s-a*i))
s -= x
yield x``````
oldj
• 139

``````import random

r = [6] * 10
for i in range(40):
r[random.choice([i for i in range(10) if r[i] < 12])] += 1
print(r)``````

[10, 10, 11, 9, 8, 10, 11, 10, 12, 9]

``````import random

r = [600] * 10
for i in range(4000):
r[random.choice([i for i in range(10) if r[i] < 1200])] += 1
r = [i / 100 for i in r]
print(r)``````

[9.65, 9.84, 10.21, 9.98, 10.06, 10.09, 10.09, 9.85, 10.12, 10.11]
fooklook
• 106

``````\$sum = 0;                 //生成随机数的和
\$total = 4000;           //随机数总和不能大于4000
\$num = 10;                //生成num个随机数
\$factor_start = 0;             //优化算法效率，在一定情况下，提高系数，可以随机数的效率。
\$factor_end = 600;             //后面能随机的值不够时，需要控制后面随机数的范围。
\$rand_num = array();
foreach(\$i==1;\$i<=\$num;\$i++){
if(\$i==10){
\$rand_num[9] = 6 + (\$total - \$sum)/100;
break;
}
do{
\$rand = mt_rand(\$factor_start,\$factor_end);
\$tmp_sum = \$sum + \$rand;
if(((\$total - \$tmp_sum) / (\$num - \$i)) < 600){
\$sum  = \$tmp_sum;
\$rand_num[] = 6 + \$rand / 100;
if(\$total - \$sum<=600){
\$factor_end = \$total - \$sum;
}
break;
}else{
\$factor_start += 100;
}
}while(true)
}
var_dump(shuffle(\$rand_num));                //重新打乱数组，并输出``````

`````` function rand_red(\$min,\$max,\$num,\$count){
\$return=[];
\$shenyu=\$count-(\$min*\$num);//每个人分6块剩余的金额
\$rand_num=\$max-\$min;//最大分配
\$mt_rand_min=1;//剩余金额最小值 默认分1
for(\$i=1;\$i<=\$num;\$i++){
\$num_count=mt_rand(\$mt_rand_min,\$rand_num);//随机分配金额
if(\$shenyu>\$num_count){
\$shenyu=\$shenyu-\$num_count;
\$mt_rand_min=\$shenyu/(\$num-\$i);//计算剩余小值
\$red_num=\$min+\$num_count;//最少分配加上 max-min随机值
\$return[]=\$red_num;
}else{
if(\$shenyu!==0){
\$red_num=\$min+\$shenyu;
\$shenyu=0;
\$return[]=\$red_num;
}else{
\$return[]=\$rand_num;
}
}
}
return \$return;
}
\$arr=rand_red(6,12,10,100);
var_dump(\$arr);
var_dump(array_sum(\$arr));

old_bin
• 175

1、每人至少6块，所以先分出60，剩下40。那剩下人的每个人能得到的初看是[0～6]；
2、反推。从最后一个人(第10个人)推起，到他时，剩下的钱必定是<=6，继续往前推一个，到他时，剩下的钱必定是<=12，然后依次类推（最好在纸上写一下）。这么推我们可以得出到第5个人得钱时，剩下的钱必定是<=36, 那么前4个人必须要分掉至少4块钱，以此再推，前5个人必定要分掉至少10块钱，至最后一个至少得分掉34块钱。这样通过找规律我们得出了每个人得钱的随机范围的第一个值。
3、虽然我们得出了每个人随机范围的第一个值，但并不是每一个人的随机范围的第二个值都是 6，因为当前面的几个人已经把大部分钱都分了的时候，后面的人就没得分了。这次，我们从第一个人开始往后推，当到第N个人时剩下的钱\$R<6时，这个人所能分得的钱的随机范围第二个值就是剩下的钱\$R，然后他后面的人所能分得的钱的随机范围的第二个值还是\$R；

``````    \$R = 40;    //剩余钱数
\$arr = array(6, 6, 6, 6, 6, 6, 6, 6, 6, 6);
for(\$i = 0; \$i<10; \$i++) {
//默认随机数是 0～6
//反推过程可以得出从第4个人开始，rand要么是以\$diff为初始值，要么就是上一行的\$rand;而随机范围第二个值由剩余钱\$R决定。
if(\$i > 2) {
if(\$R <= 0) break;
\$diff = \$R - (10 - \$i - 1) * \$add_max;
\$rand_end = \$R < 6 ? \$R : \$add_max;
\$diff > 0 && (\$rand =  mt_rand(\$diff, \$rand_end));
}

\$arr[\$i] += \$rand;
\$R -= \$rand;
}

var_dump(\$arr,array_sum(\$arr));``````

``````    \$R = 40;
\$arr = array(6, 6, 6, 6, 6, 6, 6, 6, 6, 6);
for(\$i = 0; \$i<10; \$i++) {
//根据反推，前三个是不用考虑随机范围的，从第4个人开始才需要考虑随机范围
if(\$i < 3) {
\$rand = mt_rand(0, 6);
} else if(\$i == 3) {
//留给第5个人的不能超过36。当\$rand_start不为0时，说明钱还很充足的。充足到第\$i个人必须抽走一些钱才行。

\$rand_start = \$R - 36 ? \$R - 36 : 0;
\$rand = mt_rand(\$rand_start, 6);
} else if(\$i == 4) {
//留给第6个人的不能超过30.
\$rand_start = \$R - 30 ? \$R - 30 : 0;
\$rand = mt_rand(\$rand_start, 6);
} else if(\$i == 5) {
//留给第6个人的不能超过24.到现在为止，钱一定还是充足的，所以不用考虑第二个值。
\$rand_start = \$R - 24 ? \$R - 24 : 0;
\$rand = mt_rand(\$rand_start, 6);
}

//...

else if(\$i == 6) {
//通过上面得出留给下一个人的不能超过 (10-\$i-1)*6;  然后到第7个人时，假设前面每个人都得到了6块，即只剩下4块钱时，随机范围第二个数就不再是6了，而是剩余数\$R
\$rand_start = \$R - 24 ? \$R - 24 : 0;
\$rand_end = \$R > 6 ? 6 : \$R;
\$rand = mt_rand(\$rand_start, \$rand_end);
}

//...

\$arr[\$i] += \$rand;
\$R -= \$rand;
} ``````

Jaywin
• 265

``````//  100  10   max 12 min 6
var count = 0;
var redPacket = [];
function getAmount(totalAmount,number,max,min){
count++;

var usedAmount = 0;
var amountList = [];

for(var i = 0; i< number-1; i++){
var amount = parseFloat((Math.random()*(max-min)).toFixed(2));

amountList[i] = amount;
usedAmount += amount;
}

var balance = totalAmount - min*number - usedAmount;

amountList[9] = balance;

if(balance > (max-min) || balance < 0){
getAmount(totalAmount,number,max,min);
}else{
usedAmount = 0;
for(var i = 0; i< number; i++){
redPacket[i] = (6 + amountList[i]).toFixed(2);
usedAmount += parseFloat(redPacket[i]);
}
// 确认总额是否是100
console.warn(usedAmount.toFixed(2));
// 打印每个红包金额
console.info(redPacket);
console.info('计算次数：' + count);
}
}
getAmount(100,10,12,6);``````

• 2
``````# -*- coding:utf-8 -*-
import random
#红包分配算法

def hongbao(money,num,min,max):
#arr = [min for n in range(10)]
arr =[min*100]*10
leftmoney = (money - min*num)*100
times = 0
while leftmoney > 0:
i = random.randint(0,num-1)
k = max*100 - arr[i]
if k <= 0:
pass
else:
j = leftmoney
l = (k<j and k or j)
m = random.randint(0,l)
leftmoney = leftmoney - m
arr[i]=arr[i] + m
times = times + 1
print(times)
for i in range(len(arr)):
arr[i] = arr[i]/100
return(arr)

result = hongbao(100,10,6,12)
print(result)
print(sum(result))``````

27
[10.86, 11.88, 6.19, 8.51, 9.67, 11.99, 11.96, 7.45, 11.11, 10.38]
100.0

qcheng5453
• 0

``````public class Allocation{
public static final double Total = 100;
public static final double Min = 6;
public static final double Max = 12;
public static final int peopleNum = 10;
private static double money_left;

public static double[] allocateMoney(){
double[] result = new double[10];
money_left = Total;
double lowerBound = Min;
double upperBound = Max;
double money_now = 0;
double sum = 0;
for (int i = 0; i < peopleNum ; i++) {
lowerBound = Min > money_left - Max*(peopleNum-i-1)?Min:(money_left - Max*(peopleNum-i-1));
upperBound = Max < money_left - Min*(peopleNum-i-1)?Max:(money_left - Min*(peopleNum-i-1));
money_now = (upperBound - lowerBound)*Math.random()+lowerBound;
System.out.println((i+1)+" : " + money_now);
result[i] = money_now;
//verify
sum += money_now;
money_left = money_left - money_now;
}
//verify
System.out.print("Total = " + sum);
return result;
}
public static void main(String[] args) {
allocateMoney();
}
}
``````

###### 你尚未登录，登录后可以
• 和开发者交流问题的细节
• 关注并接收问题和回答的更新提醒
• 参与内容的编辑和改进，让解决方法与时俱进