算法:php求几个数字之和刚好大于或等于某一个给定的值
经常有这样的例子,求解几个数之和最接近于给定的值,今天我们就来讨论一下另外一种情况,求几个数字之和刚好大于或等于某一个给定的值。
实际应用场景,例如一个用户在网上购物,需要购买某种商品20件,但是网上的几家店中,没有那家店单独有这么多商品,此时就需要几家店面一起凑够20件商品,考虑到发货成本,肯定参与发货店家越少越好,下面给出该算法的设计思路。
<?php
//事例:A门店某商品10件,B门店某商品20件,C门店某商品5件,D门店某商品8件,E门店某商品9件
/*设计思路:
1.一个商店能满足的情况下,不采用多个门店发货。如用户购买5件,则去C门店取,保证 门店数-购买数 最小。同理2个商店能够满足,不采用三个商店。
2.多个商店能够满足的情况下,取门店数和相加最少的项,比如(20,5),(20,9)都能满足24件购买量,取前者的配置方式,
因为20+5<20 9="" planstorearr="['A'=">'10','B'=>'20','C'=>'5','D'=>'8','E'=>'9'];
*/
$buyNum=20;
//20为用户想购买这个商品的件数,planStoreArr表示目前可供选择门店的集合 然后通过计算$planArr的子集排序取值
$planArr=getBuyStorePlan($buyNum,$planStoreArr);
//var_dump($planArr);
//商品计划购买方法
function getBuyStorePlan($buyNum,$planStoreArr){
asort($planStoreArr);
global $result;
$result=array();//进入方法前先定义全局变量存放数组所有子集
//为了便于比较,取出数组中的值单独作为数组
foreach($planStoreArr as $key=>$v){
$planVArr[]=$v;
}
build($planVArr,array(),0); //求出方案的所有子方案
$len=count($result);
//1.冒泡排序通过数组元素个数依次从大到小排列
for($i=0;$i<$len;$i++){
for($j=$i;$j<$len;$j++){
if(count($result[$j])<count($result[$i])){
$change=$result[$j];
$result[$j]=$result[$i];
$result[$i]=$change;
}
}
}
//2.在1的基础上按照和的大小从大到小排列,
for($i=0;$i<$len;$i++){
for($j=$i;$j<$len;$j++){
if((count($result[$j])==count($result[$i]))&&array_sum($result[$j])<array_sum($result[$i])){
$change=$result[$j];
$result[$j]=$result[$i];
$result[$i]=$change;
}
}
}
//上述的结果类似[[],["5"],["8"],["9"],["10"],["20"],["5","8"],["5","9"],["10","5"],["8","9"]...
//3.依次匹配到最近的一个值
$answer=array();
for($i=0;$i<$len;$i++){
if(array_sum($result[$i])>=$buyNum){
$answer=$result[$i];
break;
}
}
//4.匹配门店组装结果,取出对应的门店
for($i=0;$i<$len;$i++){
if($v==$answer[$i]){
$planArr[$k]=$v;
unset($planStoreArr[$k]);
break;
}
}
}
arsort($planArr);
$total=0;
//5.计算每个门店的发货量
foreach($planArr as $k =>$v){
$total+=$v;
if($total>$buyNum){
//echo $total;
$planArr[$k]=$v-($total-$buyNum);
break;
}
}
return $planArr;
}
?>
程序设计的关键之处在于理解所有的取值结果一定在所有门店的子集当中,然后给子集按照需求排序,便可便利得出想要的结果。