Eğer bakarsanız oezis algorithm tek dezavantajı hemen açıktır: Zaten çalışmak değil bilinen numaraları özetliyor çok zaman harcıyor. 1 + 2 zaten çok büyük ise (Örneğin,,, 1 + 2 + 3, 1 + 2 + 3 + 4 denemek için herhangi bir mantıklı 1 + 2 + 3 + 4 + 5 değil ... çok .)
Böylece geliştirilmiş bir versiyonunu yazdım. Bu biraz sihir kullanmak değildir, her şey manuel yapar. Bir dezavantajı sıralanabilir giriş değerleri gerektirir olduğunu (kullanım rsort). Ama bu büyük bir sorun olmamalı ;)
function array_sum_parts($vals, $sum){
$solutions = array();
$pos = array(0 => count($vals) - 1);
$lastPosIndex = 0;
$currentPos = $pos[0];
$currentSum = 0;
while (true) {
$currentSum += $vals[$currentPos];
if ($currentSum < $sum && $currentPos != 0) {
$pos[++$lastPosIndex] = --$currentPos;
} else {
if ($currentSum == $sum) {
$solutions[] = array_slice($pos, 0, $lastPosIndex + 1);
}
if ($lastPosIndex == 0) {
break;
}
$currentSum -= $vals[$currentPos] + $vals[1 + $currentPos = --$pos[--$lastPosIndex]];
}
}
return $solutions;
}
Oezis test programının değiştirilmiş bir versiyonu çıkışları (bitiş bakın):
possibilities: 540
took: 3.0897309780121
Oezis kod idam oysa Yani 65 seconds benim makinede (evet, benim makine çok yavaş), 3.1 seconds yürütmek için sadece aldı. Bundan daha fazla 20 times faster!
Ayrıca benim kod 540 yerine 338 olasılık bulundu ki, fark edebilirsiniz. Bunun yerine şamandıraların tamsayılar kullanmak için test programı ayarlanabilir olmasıdır. Direct floating point comparison is rarely the right thing to do, bu büyük bir örnek: neden bazen 59.959999999999 almak yerine 59.96 ve böylece maç sayılmayacaktır. Ben tamsayılar ile oezis kod çalıştırmak Yani, çok, 540 olanakları bulur ;)
Test programı:
// Inputs
$n = array();
$n[0] = 6.56;
$n[1] = 8.99;
$n[2] = 1.45;
$n[3] = 4.83;
$n[4] = 8.16;
$n[5] = 2.53;
$n[6] = 0.28;
$n[7] = 9.37;
$n[8] = 0.34;
$n[9] = 5.82;
$n[10] = 8.24;
$n[11] = 4.35;
$n[12] = 9.67;
$n[13] = 1.69;
$n[14] = 5.64;
$n[15] = 0.27;
$n[16] = 2.73;
$n[17] = 1.63;
$n[18] = 4.07;
$n[19] = 9.04;
$n[20] = 6.32;
// Convert to Integers
foreach ($n as &$num) {
$num *= 100;
}
$sum = 57.96 * 100;
// Sort from High to Low
rsort($n);
// Measure time
$start = microtime(true);
echo 'possibilities: ', count($result = array_sum_parts($n, $sum)), '<br />';
echo 'took: ', microtime(true) - $start;
// Check that the result is correct
foreach ($result as $element) {
$s = 0;
foreach ($element as $i) {
$s += $n[$i];
}
if ($s != $sum) echo '<br />FAIL!';
}
var_dump($result);