需要一個php演算法,選出一串數組中的數字組合相加和要最接近(<=)給定值的演算法。
例如 :上限值:38 給定數組值 15,20,10, 6
正確結果選定:20 10 6
這個要如何??求具體實現方式
之前是按從大到小排序,再相加,發現選出 20 15 10,但是其實最優的是20 10 6,求協助。。。
回複內容:
需要一個php演算法,選出一串數組中的數字組合相加和要最接近(<=)給定值的演算法。
例如 :上限值:38 給定數組值 15,20,10, 6
正確結果選定:20 10 6
這個要如何??求具體實現方式
之前是按從大到小排序,再相加,發現選出 20 15 10,但是其實最優的是20 10 6,求協助。。。
$a = 38;
$arr = array(15,20,10,6);
function ss($a,$arr){
$count = count($arr);$array = array();for($i=0;$i<$count;$i++){ $r = $arr[$i]; unset($arr[$i]); $sum = abs(array_sum($arr) - $a); $array[$sum][] = $arr; $arr[] = $r;}return $array;
}
$dd = ss($a,$arr);
ksort($dd);
print_r($dd);
列印,絕對值最小的,最靠近
Array
(
[2] => Array ( [0] => Array ( [1] => 20 [2] => 10 [3] => 6 ) )[3] => Array ( [0] => Array ( [3] => 6 [4] => 15 [5] => 20 ) )[7] => Array ( [0] => Array ( [2] => 10 [3] => 6 [4] => 15 ) [1] => Array ( [4] => 15 [5] => 20 [6] => 10 ) )
)
最先想到的肯定是暴力for迴圈演算法,這個時間複雜度有點高,在n^2,少量資料可以實現的。
結果是 20 15 10 和明顯小於38了啊,if判斷就可以篩選掉,不可能一次性就給你選出最優,除非剛好。
演算法的話可以劃分到動態規劃裡面去,核心也是for迴圈,很類似。
這是經典背包問題,推薦閱讀 背包問題九講
利用了動態規劃求解01背包問題的方法
$maxSize = 38;$arr = array(15, 20, 10, 6);$result = array();$answers = array();$currSize = 36;$len = count($arr);for ($i = 0; $i < $len; $i++) { $result[] = array(); for ($j = 0; $j <= $maxSize; $j++) { $result[$i][$j] = 0; }}for ($i = 0; $i <= $maxSize; $i++) { for ($j = 0; $j < $len; $j++) { if ($arr[$j] > $i) { if ($j === 0) $result[$j][$i] = 0; else $result[$j][$i] = $result[$j - 1][$i]; } else { if ($j === 0) $result[$j][$i] = $arr[$j]; else $result[$j][$i] = max($result[$j - 1][$i], $result[$j - 1][$i - $arr[$j]] + $arr[$j]); } }}// 找出答案for ($i = $len - 1; $i >= 0 && $currSize !== 0; $i--) { if ($result[$i][$currSize] - $result[$i - 1][$currSize - $arr[$i]] === $arr[$i]) { $answers[] = $arr[$i]; $currSize -= $arr[$i]; }}
求助,求助~update