您的位置:首页 > 编程语言 > PHP开发

PHP 金额均衡分配算法

2020-06-29 04:43 411 查看
$Money = array(
    1,2,3,3,4,4,5,5,6,6,7,7,8,8,9,10
);

$Res = AccordingToMPA($Money, array(
'1'=>'Admin','2'=>'张三','3'=>'庆庆','4'=>'鹏鹏',
'5'=>'Admin','6'=>'张三','7'=>'庆庆','8'=>'鹏鹏',
));

print_r($Res);

/**
  *函数名称: AccordingToMPA		作者: Dandy.Mu
  *谱写日期: 2014-09-19 14:27:05
  *函数说明: 根据金额和比例进行平均分配
  *参数说明: 
* @Param
  *返回信息: 
  */
function AccordingToMPA(Array $Amount_pool, Array $Users)
{
if ( !is_array($Amount_pool) || !count($Amount_pool) || !is_array($Users) || !count($Users) ) return false;
// 不改变索引情况的排序
asort($Amount_pool);
// 声明存储最后返回的数据的数组
$retData = array();
// 计算过程中用到的临时数据存放点
$tmpData = array(
// 待分配数据的金额的和
'Total_amount' => array_sum($Amount_pool),
// 待分配数据的金额总数量 是数量 不是金额的汇总
'The_total_number_of_money' => count($Amount_pool),
// 待分配数据的用户总数
'The_total_number_of_users' => count($Users),
);
// 第一次循环的分配是先分大的还是先分小的 true 等于先分大的
$Direction = true;
// 人员平均金额最大限额
$tmpData['Maximum_limit_money'] = ceil($tmpData['Total_amount'] / $tmpData['The_total_number_of_users']);
while ($Amount_pool)
{
// 最大组合数
$Combination_maximum = floor($tmpData['The_total_number_of_money'] / $tmpData['The_total_number_of_users']);
// 判断当前这轮循环是求大还是求小
$Larger_or_smaller = $Direction === true ? 'Large' : 'Smaller';
// 循环所有待分配数据的用户
foreach ($Users as $ID => $Name)
{
// 预期的最大值 = 人均金额 - 当前用户已经拥有的金额数
$Expected_maximum = $tmpData['Maximum_limit_money'] - $tmpData[$ID]['Total_amount'];
// 分析待分配数据的Key
$tmpAmount_pool_key = Find_similar_value($Amount_pool, $Expected_maximum, $Combination_maximum, $Larger_or_smaller);
// 这个变成false的原因多数是因为数据已经分配完了,也就是木有了啊。 有木有
if ( $tmpAmount_pool_key === false ) break;
// 最终的实际返回的数据
$retData['iD'][$ID][] = $tmpAmount_pool_key;
$retData['Money'][$ID] += $Amount_pool[$tmpAmount_pool_key];
// Keys 当前分配人员分到的所有的Key 	【测试的时候使用】
// Money 当前分配人员分到的所有的金额值 【测试的时候使用】
// Total_amount 当前分配人员的总金额	【测试的时候使用】
$tmpData[$ID]['Keys'][] = $tmpAmount_pool_key;
$tmpData[$ID]['Money'][] = $Amount_pool[$tmpAmount_pool_key];
$tmpData[$ID]['Total_amount'] += $Amount_pool[$tmpAmount_pool_key];
// 清理已经赋值的
unset($Amount_pool[$tmpAmount_pool_key]);
// 剩余可分配的数据减1
--$tmpData['The_total_number_of_money'];
// 判断如果当前用户的平均金额已经满足 就将其剔除出分配组
if ( $tmpData[$ID]['Total_amount'] >= $tmpData['Maximum_limit_money'] ) 
{ unset($Users[$ID]); --$tmpData['The_total_number_of_users']; }
}
// 逆转方向
$Direction = $Direction === true ? false : true;
}
unset(
$Amount_pool, $Users, $tmpData, $Direction, $Combination_maximum, 
$Larger_or_smaller, $Expected_maximum, $tmpAmount_pool_key
);
return $retData;
}
/**
  *函数名称: Find_similar_value		作者: Dandy.Mu
  *谱写日期: 2014-09-19 14:01:07
  *函数说明: 查找符合规则的数值
  *参数说明: 
* @Amount_pool         => 数据源也就是剩余为分配的数据的数组
* @Expected_maximum    => 预期的最大值
* @Combination_maximum => 最大组合数,也就是当前这个人还能分配的最大的个数
* @Larger_or_smaller   => 期待值 求大 或者 求小,[Large(求能接受的最大值)], 不等于 Large 则为求最小值
* @Sort                => 是否进行排序,正常情况一定在外面排序好才调用,所以默认为false
  *返回信息: 符合条件的 Amount_pool 的数组的 Key
  */
function Find_similar_value(Array $Amount_pool, $Expected_maximum, $Combination_maximum, $Larger_or_smaller = 'Large', $Sort = false)
{
if ( !is_array($Amount_pool) || !count($Amount_pool) || !is_numeric($Expected_maximum) || !is_numeric($Combination_maximum) ) return false;
if ( $Sort === true ) asort($Amount_pool);
// 如果是求最小值那么返回第一个就完事了
if ( $Larger_or_smaller !== 'Large' ) { return key($Amount_pool); }
// 如果预期的最大组合小于2那么就是1了吗 直接返回一个最大的就O了
if ( $Combination_maximum < 2 ) { end($Amount_pool); return key($Amount_pool); }
// 克隆一个对象用正向循环
$Amount_pool_clone = $Amount_pool;
// 预期的值最大值 也就是 预期值加上组合数
$Expected_maximum_Puls_Combination = $Expected_maximum + $Combination_maximum;
// 真实的循环次数 因为第一个循环中已经将最大的值赋值了 所以知识正向的相加最小的而已
$Real_Combination = --$Combination_maximum;
while ($retData = end($Amount_pool))
{
// 逆向循环数组那么肯定是大到小的顺序,如果当前值大于了预期最大值就跳过循环。
if ( $retData > $Expected_maximum_Puls_Combination ) { array_pop($Amount_pool); continue; }
reset($Amount_pool_clone);
for ($i=0; $i < $Real_Combination; $i++)
{ $retData += current($Amount_pool_clone); next($Amount_pool_clone); }
// 上面计算后的值 如果小于期待的值 就证明三个数字组合的最大的数字就是当前这个了
if ( $retData <= $Expected_maximum )
{ 
$retData = key($Amount_pool); 
unset($i, $Expected_maximum, $Combination_maximum, $Amount_pool, $Larger_or_smaller, $Sort, $Amount_pool_clone, $Expected_maximum_Puls_Combination);
return $retData;
}
array_pop($Amount_pool);
}
// 如果以上实在没有匹配就返回一个最小的
reset($Amount_pool_clone); $retData = key($Amount_pool_clone); 
unset($i, $Expected_maximum, $Combination_maximum, $Amount_pool, $Larger_or_smaller, $Sort, $Amount_pool_clone, $Average_Puls_Combination);
return $retData;
}
[/code]

转载于:https://my.oschina.net/CocoFather/blog/318483

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: