It came to me! The "present layer" of the recursion does this:
- Sum the charge amounts.
- Iterate through the array of charges, subtracting out 1 charge at a time and test against the target batch amount.
- If the amount matches in this iteration, unset the id of this charge and return the array of results.
- If not found, iterate again through the array of charges this time removing the current charge. call the function again with the same target amount and the new shortened array to the same function again.
Working code (Github has newer optimizations, too):
$charges=Array(
'2863996511' => 154.00 ,'2863879671' => 10.88
,'2863992361' => 762.20 ,'2863858891' => 209.00
,'2863898975' => 49.00 ,'2863856334' => 148.00
,'2863894564' => 5.44 ,'2863367273' => -25.01
); print_r($charges);
$targets=Array(1302.63, 1327.64, 1322.20 );
foreach( $targets as $batch ) {
printf( "We seek combination of transIds to = $%-7.2f\n", $batch);
$answer=reco( $batch, $charges );
if( is_array($answer) )
echo eval( "return ".implode("+",$answer).";" )."\nWIN!\n";
else
echo "Bust!\n";
}
function reco( $target, $arr ){
if( count($arr) < 2 )
return FALSE;
$killid='';
$sum = eval( "return ".implode("+",$arr).";" );
foreach( $arr as $id=>$amt ){
if( abs($sum-$target-$amt) < .01 ) {
$killid=$id;
break;
}
}
if( strlen($killid) > 1 ) {
echo ". omit $killid : ".$arr[$killid]."\n";
unset($arr[$killid]);
return $arr;
}
foreach( $arr as $id=>$amt ){
$tmp=$arr;
unset($tmp[$id]);
$rtn = reco( $target, $tmp );
if( is_array($rtn) ) {
echo ".. omit $id : ".$arr[$id]."\n";
return $rtn;
}
}
return FALSE;
}
And the output:
We seek combination of transIds to = $1302.63
. omit 2863879671 : 10.88
1302.63
WIN!
We seek combination of transIds to = $1327.64
. omit 2863367273 : -25.01
.. omit 2863879671 : 10.88
1327.64
WIN!
We seek combination of transIds to = $1322.20
. omit 2863367273 : -25.01
.. omit 2863879671 : 10.88
.. omit 2863894564 : 5.44
1322.2
WIN!
Performance isn't a great concern; to the third level of recursion processed in about a second.