0

I am basically trying to solve the coin change problem through recursion and here is what i have so far -:

#include<iostream>
#include<conio.h>
using namespace std;

int a[]={1,2,5,10,20,50,100,200},count=0;

//i is the array index we are working at
//a[] contains the list of the denominations
//count keeps track of the number of possibilities

void s(int i,int sum) //the function that i wrote
{
    if (!( i>7 || sum<0 || (i==7 && sum!=0) )){

    if (sum==0) ++count; 

    s(i+1,sum);
    s(i,sum-a[i]);

    }
}


int c(int sum,int  i ){  //the function that I took from the algorithmist
    if (sum == 0)
        return 1;
    if (sum < 0)
        return 0;
    if (i <= 0 && sum > 0 )
        return 1;

    return (c( sum - a[i], i ) + c( sum, i - 1 ));
}
int main()
{
    int a;
    cin>>a;

    s(0,a);
    cout<<c(a,7)<<endl<<count;

    getch();
    return 0;
}

The first function that is s(i,sum) has been written by me and the second function that is c(sum,i) has been taken from here - (www.algorithmist.com/index.php/Coin_Change).

The problem is that count always return a way higher value than expected. However, the algorithmist solution gives a correct answer but I cannot understand this base case

if (i <= 0 && sum > 0 ) return 1;

If the index (i) is lesser than or equal to zero and sum is still not zero shouldn't the function return zero instead of one?

Also I know that the algorithmist solution is correct because on Project Euler, this gave me the correct answer.

Ambar
  • 112
  • 11
  • 3
    Can you describe your algorithm in simple steps in English? That is the first step, and from there on you can implement. I would not have used the algorithm that you copied, nor the one you implemented... But I can describe it in simple steps, and from there it's easy to implement. – David Rodríguez - dribeas Apr 30 '12 at 12:08
  • @DavidRodríguez-dribeas Well, I can give a description in terms of opening of branches/nodes in the recursion tree-For each member in the denominations array I open a node in which that element is included in the sum[i.e s(i,sum-a[i])] and another one in which that element is not included in the sum and the function moves on to the next element of the array[i.e. s(i+1,sum)]. This way every time sum becomes zero, I increment count. What am i doing wrong? – Ambar Apr 30 '12 at 17:41
  • That description is very far from plain english, consider that you were explaining the problem an the solution to your grandmother, how can you provide the exact change? (By reducing the problem into something *smaller*). For example, to return change worth X, pick the highest denomination value, if X is greater than the denomination D, then return one coin for that denomination and solve the problem for X-D, if X is smaller than D, then no more coins of that denomination can be yielded and try to return X by using a subset of the denominations removing the D. – David Rodríguez - dribeas Apr 30 '12 at 17:50
  • ... The two recursive steps are guaranteed to reduce the problem, either by having a smaller value to return or a smaller set of denominations to use, so that is fine. When do you need to stop, of course if the value to return is 0, or if you run out of denominations (which will not be the case with your set of denominations). See? plain english, no search trees or arrays or functions... – David Rodríguez - dribeas Apr 30 '12 at 17:51

2 Answers2

0

I believe the algorithm to be biased towards the choice of denominations, and assumes that there will be only one coin of the smallest denomination. Consider as a counter example of the correctness that there was no 2 coins, just 1,5,... And that the target to return was 4:

 (4,1)
    (-1,1)  -> cut, sum<0 a[1]==5
    (4,0)   -> i==0 => 1

Either that or you misimplemented the algorithm (can there be an off by one error? Could it be i<0, or the original array be 1-based?)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • I am sorry for the confusion, the problem statement actually is - Given an unlimited supply of each type of coin, find the number of ways to make the sum. – Ambar Apr 30 '12 at 17:55
0

I guess that your problem is "Assuming that I have unlimited support of coins, on how many ways can I change the given sum"? The algoritimists solution you gave assumes also, that the smallest denomination is 1. Otherwise it will won't work correctly. Now your question:

if (i <= 0 && sum > 0 ) return 1;

Notice, that the only possibility that i<0 is that you called it with this value - no recursive call will be made with negative value of i. Such case (i<0) is an error so no result is proper (maybe assertion or exception would be better). Now if i=0, assuming that at index 0 there is coin of value 1 means that there is only one way to exchange sum with this denomination - give sum coins of value 1. Right?

After a moment of thought I found out how to remove assumption that a[0] == 1. Change

if (i <= 0 && sum > 0 ) return 1;

into

if (i <= 0 && sum > 0 ) return sum % a[0] == 0 ? 1 : 0;
Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83
  • Thanks, that pretty much cleared my confusion. And the answer given by the algoritimist's function was giving the correct answer because a[0] (in this particular case) _is_ equal to 1. Also, I figured out why my solution was incorrect- at _every_ level in the recursion tree, whenever I was getting s(i,sum)==1, count was incremented, which means that every possibility was being counted many times! I will modify the code accordingly. – Ambar Apr 30 '12 at 17:53