算法: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;
	}
?>

程序设计的关键之处在于理解所有的取值结果一定在所有门店的子集当中,然后给子集按照需求排序,便可便利得出想要的结果。

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑夜开发者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值