5

Since standing at the point of sale in the supermarket yesterday, once more trying to heuristically find an optimal partition of my coins while trying to ignore the impatient and nervous queue behind me, I've been pondering about the underlying algorithmic problem:

Given a coin system with values v1,...,vn, a limited stock of coins a1,...,an and the sum s which we need to pay. We're looking for an algorithm to calculate a partition x1,...,xn (with 0<=xi<=ai) with x1*v1+x2*v2+...+xn*vn >= s such that the sum x1+...+xn - R(r) is maximized, where r is the change, i.e. r = x1*v1+x2*v2+...+xn*vn - s and R(r) is the number of coins returned from the cashier. We assume that the cashier has an unlimited amount of all coins and always gives back the minimal number of coins (by for example using the greedy-algorithm explained in SCHOENING et al.). We also need to make sure that there's no money changing, so that the best solution is NOT to simply give all of the money (because the solution would always be optimal in that case).

Thanks for your creative input!

Degustaf
  • 2,655
  • 2
  • 16
  • 27
Treecj
  • 427
  • 2
  • 19
  • Belongs on [cstheory](http://cstheory.stackexchange.com/) – bobobobo Feb 09 '11 at 19:14
  • If you always have the lowest possible amount of coins with you (if you played this game each time in the supermarket before), then you can calculate it using the approach of giving all your coins and then calculate what would be given back and substract this change from your current belongings. – eumiro Feb 09 '11 at 19:21
  • 3
    @bobobobo I don't think this would be considered a [research-level question](http://cstheory.stackexchange.com/faq), it's a rather common problem and not suitable for cstheory. – Kiril Feb 09 '11 at 19:29
  • What are your coin denominations? Are they such that the greedy algorithm for making change always gives the minimum number of coins? – IVlad Feb 09 '11 at 21:29
  • @eumiro: Yeah I also stumbled across this solution, but I'm not sure yet if it will suffice all cases (especially if the cashier might return less for the sum s+1 than for s)... – Treecj Feb 09 '11 at 21:52
  • @IVlad: The coin-system mustn't necessarily be 'greedy-friendly' but I guess we should assume that it is.. – Treecj Feb 09 '11 at 21:53

1 Answers1

1

If I understand correctly, this is basically a variant of subset sum. If we assume you have 1 of each coin (a[i] = 1 for each i), then you would solve it like this:

sum[0] = true
for i = 1 to n do
    for j = maxSum downto v[i] do
        sum[j] |= sum[j - v[i]]

Then find the first k >= s and sum[k] is true. You can get the actual coins used by keeping track of which coin contributed to each sum[j]. The closest you can get your sum to s using your coins, the less the change will be, which is what you're after.

Now you don't have 1 of each coin i, you have a[i] of each coin i. I suggest this:

sum[0] = true
for i = 1 to n do
    for j = maxSum downto v[i] do
       for k = 1 to a[i] do
           if j - k*v[i] >= 0 do
               sum[j] |= sum[j - k*v[i]] <- use coin i k times

It should be fairly easy to get your x vector from this. Let me know if you need any more details.

IVlad
  • 43,099
  • 13
  • 111
  • 179
  • Thanks a lot @IVlad - very nice solution and good explanation! In fact I also had the subset problem somewhere in my mind, but didn't come to an solution with it. The only question remaining is: Can we always be sure that the solution with the least change is correct? Might it possible that a partition exists where we have a higher amount of change, but end up having less coins than in the solution with minimal change? I'm thinking of a change like 4 cents which requires at least 2 coins (2x2) whereas a change of 5 cents only requires 1 coin... – Treecj Feb 10 '11 at 15:31
  • @Toby - that's true, good catch. To fix that you would have to iterate `k` from `s` to `maxSum` and for each `sum[k] = true`, run a minimum number of coins for change algorithm on `k - s`, and keep that minimum. I realize this isn't very efficient, but it's all I got so far. I'll give it some more thought and let you know if I can come up with anything better. – IVlad Feb 10 '11 at 17:04