最近碰到一些情况,把思路重新整理了一下,敲出代码。记下来,以后可以借鉴,进一步优化等。

大致的思路:红包主要分两种,一种是平均分配,一种是随机分配。

1、平均分配

  平均分配相对好理解,只要把钱平均分给每一个人就可以了

  这里有一个情况,就是钱的总额是固定的,但是分配的人数,不一定可以整除余0,那么剩下的如何分配呢?

  这里,剩余的钱(极少),多分到的人,也就是多分1分钱(在计算处理时,单位是“分”)

  所以,使用的处理办法是,从前到后(谁手快,谁多分,蚊子再小也是肉),逐一分这剩余的钱,每人1分钱,直到钱没为止

2、随机分配

  我这个随机分配,比较简单,只比平均分配多了一个步骤(此步骤根据需要,可以循环多次使用)。

  先是随机分配的两个特殊情况:

    a.总金额不够所有人分。例如,最小的钱是1分钱,分给10个人。是不可以的

    b.总金额正好只能每人平均分1分钱。例如,0.1元,分给10个人,任何一个人多1分钱,就会有人没钱分

  这两个特例单独处理

  接下来的情况就是,正常的随机分钱,为了尽量让每个人分钱的概率差不多,用了下边的方法

    a.先将钱按当前分钱的人数计算平均值

    b.随机的钱数的取值范围是(1,平均值)

    c.可以分配的总钱数减去生成的随机钱数,得到下一次分配时的可分配总钱数

    d.重复a~c步骤,最终完成随机分配

  按照以上的方法随机分完之后,消耗的总金额是一定小于等于输入的总金额的,那么,在处理完随机分配之后,还要对剩余的金额处理

  这里实现的,就是将剩余的金额,再用平均分配的方式,分散到每一个人的手里

以上就是实现发红吧的大致思路,下边代码,就是根据这个思路整理而成

一、rand_money方法,完成一次随机分配

 /*
* 随机分钱
* 参数:$money,参与分钱的金额
*    $num,参与分钱的人数
*/
function rand_money($money, $num)
{
$arr = [];//结果数组
$money = $money * 100;// 将元转成分(小数计算有误差,随机数也都是整数)
$rest_money = $money;// 初始化,剩余钱的变量
$average = $rest_money / $num;// 求出均分情况下,每人的红包值 if ($average < 1) {// 钱不够所有人分
return false;
}elseif($average == 1){// 所有人平均分这笔钱(钱数只够这么分的)
for ($i=0; $i<$num; $i++) {
$arr[] = $average;
}
}else{// 每个人随机分配
for ($i=0; $i<$num; $i++) {
$range_money = round(($rest_money / ($num - $i)));
$rand_money = mt_rand(1, $range_money);
$arr[] = $rand_money;
$rest_money = $rest_money - $rand_money;// 获取剩下的钱
}
}
return $arr;
}

二、average_money方法,既可以自己完成平均分配,又可以协助随机分配,完成剩余金额的分配

 function average_money($money, $num, $arr=[], $conversion_val=1)
{
$money = $money * 100;
$arr_sum = 0;//保存数组和
if (count($arr) > 0) {// 随机分配,会调用此方法将剩余的钱分掉,此数组为随机分配后的结果
foreach ($arr as $k=>$v) {
$arr[$k] = $v * 100 / $conversion_val;// 如果单位有变化这调整一下,一直以分为单位处理数据
}
$arr_sum = array_sum($arr);// 统计随机分配已经分配了总钱数
} else {
for ($i=0; $i<$num; $i++) {
$arr[] = 0;// 初始化每个人的数组,兼容下边循环处理部分
}
}
$add_money = $money - $arr_sum;
// 如果总钱数和之前随机分配的数组的总和差值为0,就说明随机分配已经将钱全部分出去了,就不需要再平均分配处理了
if ($add_money == 0) {
return $arr;
}
// 先把剩余的能均分的部分均分一下,然后若再有剩余,则从前到后,注意分配
for ($i = 0; $i < $num; $i++) {
$arr[$i] = $arr[$i] + floor($add_money / $num);// 如果之前有随机分配,则是将剩余的钱平均追加入随机分配的值里
}
$arr_sum = array_sum($arr);// 分配后,求和,用于修正最后剩余的零钱
// 如果还有剩余,这部分说明每人一分都不够,就从头开始没人一分的分下去,直到分完为止
$odd_money = bcsub($money, $arr_sum, 0);// 针对钱的计算,建议使用bc函数,普通的计算方法有误差
$i = 0;
while ($odd_money >= 1) {
$arr[$i] = $arr[$i] + 1;// 每人加1分钱
$odd_money = $odd_money - 1;// 剩余的金额,每分掉一个人,就减1分钱
$i++;
}
return $arr;
}

三、红包调用方法,根据不同类型,返回不同红包的结果

 /*
* 红包方法
* 参数:$money,参与分钱的金额
*    $num,参与分钱的人数
*    $type,红包类型,0平均分配,1随机分配
*/
function get_red ($money, $num, $type=0) {
if ($type) { // 非0,随机红包
$arr_rand = rand_money($money, $num);// 先随机分配
$arr = average_money($money, $num, $arr_rand, 100);// 再平均分配
} else { // 平均分配红包
$arr = average_money($money, $num);
}
return $arr;
}

四、实例代码测试

 $a = get_red(66.61, 11, 0);
//将最终结果,转换成元为单位
foreach ($a as $k=>$val) {
$a[$k] = $val / 100;
}
print_r($a);
echo '<br />'.array_sum($a); $r = get_red(66.61, 11, 1);
//将最终结果,转换成元为单位
foreach ($r as $k=>$val) {
$r[$k] = $val / 100;
}
echo '<br />';
print_r($r);
echo '<br />'.array_sum($r);

以上的代码,就完成了红包的操作。

这代码只是,简单的实现。这其中还有特殊情况,比如,每次随机的数都是最小的数,虽然概率很低。

那么这种情况,只做一次随机分配,貌似效果并不好。毕竟后边就是平均分配了,这样每一个人的终值非常接近平均值。

所以,可以考虑,在一次随机分配之后,计算已分配总钱数,根据该总钱数判断是否需要再次进行随机分配,然后将两次或者多次随机分配的值同key合并。

最后再把剩余的金额“平均分配”后,同key加到一起。这样的结果效果更好。

注意:

1、日常人们习惯金钱的单位都是“元”,但这里,尽量转成“分”;小数计算误差大,随机数生成也都是整数

2、如果可以,金钱在计算时,尽量使用bc高精度函数。如:bcadd(加),bcsub(减),bcmul(乘),bcdiv(除)等

PHP实现简单发红包(随机分配,平均分配)的更多相关文章

  1. python+redis简单实现发红包程序

    redis是什么? Redis 是一个高性能的key-value数据库! 想进一步了解请移步搜索引擎自行查找. 编写这个小程序的目的就是对redis进行一个简单的小操作,对redis有一个初步的了解, ...

  2. php简单随机实现发红包程序

    前言: 使用PHP发红包,当我们输入红包数量和总金额后,PHP会根据这两个值进行随机分配每个金额,保证每个人都能领取到一个红包,每个红包金额不等,就是要求红包金额要有差异,所有红包金额总额应该等于总金 ...

  3. 用Python编写简单的发红包程序和计算器原理

    用Python编写简单的发红包程序: 第一种解法:数轴方法解决 import random def red_packet(money,num): money = money * 100 #将钱数转换成 ...

  4. 使用PHP编写发红包程序

    使用PHP编写发红包程序 http://www.jb51.net/article/69815.htm 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2015-07-22   微信发红 ...

  5. PHP+Ajax手机移动端发红包实例

    基本流程:当输入完红包数量和总金额后,PHP会根据这两个值进行随机分配每个金额,保证每个人都能领取到一个红包,且每个红包金额不等,并且所有红包金额总额等于总金额. 实现原理:设定总金额为10元,有N个 ...

  6. PHP实现发红包程序

    我们先来分析下规律. 设定总金额为10元,有N个人随机领取: N=1 第一个 则红包金额=X元: N=2 第二个 为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数. 第 ...

  7. PHP实现发红包程序(helloweba网站经典小案例)

    我们先来分析下规律. 设定总金额为10元,有N个人随机领取: N=1 第一个 则红包金额=X元: N=2 第二个 为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数. 第 ...

  8. 微信小程序发红包

    背景: 近期一个朋友公司要做活动,活动放在小程序上.小程序开发倒是不难,不过要使用小程序给微信用户发红包,这个就有点麻烦 确定模式: 小程序目前没有发红包接口,要实现的话,只能是模拟红包,即小程序上做 ...

  9. Python写随机发红包的原理流程

    首先来说说要用到的知识点,第一个要说的是扩展包random,random模块一般用来生成一个随机数 今天要用到ramdom中unifrom的方法用于生成一个指定范围的随机浮点数通过下面的图简单看下: ...

随机推荐

  1. Oracle同义词(synonym)

    oracle的同义词总结   从字面上理解就是别名的意思,和视图的功能类似.就是一种映射关系.   同义词拥有如下好处:   节省大量的数据库空间,对不同用户的操作同一张表没有多少差别;   扩展的数 ...

  2. 写jquery插件(转载)

    如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui 内置web项目里了.至于使用jquery好处这里就不再赘述了,用过的都知道.今天我们来讨论下jq ...

  3. Could not find or load main class org.apache.spark.deploy.yarn.ApplicationMaster

    Spark YARN Cluster mode get this error "Could not find or load main class org.apache.spark.depl ...

  4. what is spring-cloud

    什么是Spring-cloud ? Spring Cloud是一系列框架的集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载均 ...

  5. 五、Java基础加强

    Java基础加强 1.MyEclipse的使用工作空间(workspace).工程(project)在eclipse下Java程序的编写和运行,及java运行环境的配置.快捷键的配置,常用快捷键:内容 ...

  6. fiddler 修改

    很多新手学习fiddler抓包的同学们都会对https网站抓包难或者抓不起来的问题无所适从,想寻求解决办法,没问题,这节课就来解决你的疑问! 最典型的网站就是目前的百度网站了,百度在近些年采用了htt ...

  7. web 容器

    jboss简单使用(AS7): 将项目打成war包,放到jboss-as-web-7.0.0.Final\standalone\deployments下 访问 alias .name+port+war ...

  8. 2018-2019-2 20165330《网络对抗技术》Exp5 MSF基础应用

    目录 基础问题 相关知识 实验目的 实验内容 实验步骤 离实战还缺些什么技术或步骤? 实验总结与体会 实验目的 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路 返回目 ...

  9. VB调用C# dll

    cd C:\Windows\Microsoft.NET\Framework\v4.0.30319注册regasm myTest.dll /tlb:myTest.tlb

  10. 011-MAC 设置环境变量path的几种方法

    一.概述 首先要知道你使用的Mac OS X是什么样的Shell,使用命令 echo $SHELL 如果输出的是:csh或者是tcsh,那么你用的就是C Shell. 如果输出的是:bash,sh,z ...