0

Given an array of integers, A1, A2, ..., An, and integers P, C.

Find a count C of sets of integers from array A where the sum is as close to P as possible and as many elements as possible should be used.

Example

A = [3, 7, 2, 7, 25, 10, 5, 12, 1]
P = 15
C = 4

S1 = [3, 5, 7] = 15
S2 = [2, 5, 7, 1] = 15
S3 = [3, 5, 7, 1] = 16
S4 = [2, 7, 7] = 16
Ogelami
  • 366
  • 1
  • 14
  • Sounds like a homework... – Dmitry Zaets Sep 30 '14 at 11:03
  • I can ensure it is not, it's an algorithm for selecting a set of valuables from a trade for an approximate value. Just because i did not start my question with "I'm trying to" doesn't mean it's homework. – Ogelami Sep 30 '14 at 11:04
  • This is NP complete (easy to show reduction from subset sum), so there won't be a viable algorithm for large n. – interjay Sep 30 '14 at 11:09
  • That was what i was afraid of, size of A will sometimes be huge is there a way to bruteforce or pick something close to until we find values that are close enough? – Ogelami Sep 30 '14 at 11:12
  • What would be the function that evaluates a solution? For example, it is not clear if S1 (perfect target but only three elements) is better (or worse) than S3 (close but four elements). – Patrice Gahide Sep 30 '14 at 11:23
  • abs(P - sum(S)) = 0 would be the perfect match, everything higher than that would be at a higher offset in the array of the sets. – Ogelami Sep 30 '14 at 11:24

2 Answers2

0

This is a recursive solution i came up with, but it does not really cut it, sorry if it's not the prettiest code snippet and that is why i came here.

$A = array();
$P = rand(1000, 9999) / 100;

for($i = 0; $i < 100; $i++)
    $A []= rand(100, 999) / 100;

print_r(array($P, $A));

for($i = 0, $ASz = count($A); $i < $ASz; $i++)
{
    $Aclone = $A;

    array_splice($Aclone, $i, 1);

    $result = foo($Aclone, $P, array($A[$i]));

    print_r(array($result, array_sum($result)));
}

function foo($A, $P, $Set)
{
    $lowest = abs($P - array_sum($Set));
    $lowestS = $Set;
    $popVal = -1;

    foreach($A as $offset => $newNum)
    {
        $Pr = $Set;
        $Pr []= $newNum;

        $qDist = abs($P - array_sum($Pr));

        if($qDist < $lowest)
        {
            $lowestS = $Pr;
            $lowest = $qDist;
            $popVal = $offset;
        }
    }

    if($popVal == -1)
        return $Set;

    $tempA = $A;
    array_splice($tempA, $popVal, 1);

    return foo($tempA, $P, $lowestS);
}

Test : http://sandbox.onlinephpfunctions.com/code/4a3dcd9af8b9a4561903007ccea343d745b8ab71

Ogelami
  • 366
  • 1
  • 14
0

It is actually same as the popular problem "change making.". checkout the link for detail and code implementation of the algorithm:

http://karmaandcoding.blogspot.in/2012/01/coin-change-problem-with-limit-on.html

Coin change with limited number of coins

Community
  • 1
  • 1
abhinash
  • 188
  • 10
  • I'ts not really the standard coin change problem since it should make use of as many integers from the array as possible. – Ogelami Sep 30 '14 at 13:40