pranay_teja
11/29/2018 - 8:02 AM

CoinChange-Ways

#include<bits/stdc++.h>
using namespace std;

// #DynamicProgramming #StandardProblem

//==============( TopDown )==============
// https://www.youtube.com/watch?v=k4y5Pr0YVhg
int coinChangeTD(int sum, vector<int> coins, int currInd){
    if(sum==0){
        return 1; // only one way to make change for 0 ( with no coins)
    }
    if(sum<0){
        return 0; // invalid case
    }
    // every stage can be reached from previous stages
    int ways=0;
    // start from currInd to avoid repetetive combinations ex: 211 112
    for(int i=currInd; i<coins.size(); i++){
        ways+=coinChangeTD(sum-coins[i],coins,i);
    }
    return ways;
}
int coinChangeTD(int sum, vector<int> coins){
    return coinChangeTD(sum,coins,0);
}
// Memoization
// https://www.geeksforgeeks.org/coin-change-dp-7/
int coinChange1(int sum, vector<int> coins, int index){
    if(sum==0){
        return 1; // sum=0 can be produced in a single way
    }
    if(index>=coins.size()){
        return 0;
    }
    int with=0;
    if(coins[index] <= sum){ // if we can make change with current coin
        with=coinChange1(sum-coins[index],coins,index);
    }
    int without=coinChange1(sum,coins,index+1);
    return with+without;

}
int coinChange1(int sum, vector<int> coins){
    return coinChange1(sum,coins,0);
}

// https://www.youtube.com/watch?v=sn0DWI-JdNA
int coinChange2(int sum, vector<int> coins, int index){
    if(sum==0){
        return 1;
    }
    if(index>=coins.size()){
        return 0;
    }
    int amountWithCoin=0;
    int ways=0;
    while(amountWithCoin<=sum){
        int remaining=sum-amountWithCoin;
        ways+=coinChange2(remaining,coins,index+1);
        amountWithCoin+=coins[index];
    }
    return ways;
}
int coinChange2(int sum, vector<int> coins){
    return coinChange2(sum,coins,0);
}

//====================( BottomUp )=================
int coinChangeBU(int sum, vector<int> coins){
    int n=coins.size();
    vector< vector<int> > dp(sum+1, vector<int> (n+1) );
    // base cases
    for(int amount=1; amount<=sum; amount++){
        dp[amount][0]=0; // no coins
    }
    for(int numCoins=0; numCoins<=n; numCoins++){
        dp[0][numCoins]=1; // one way to make change for 0
    }

    for(int amount=1; amount<=sum; amount++){
        for(int numCoins=1; numCoins<=n ; numCoins++){
            int with=0;
            // NOTE:
            // here numCoins is not index for coins array
            // for accessing coins arra index will be numCoins-1
            if(coins[numCoins-1] <= amount ){
                int remaining = amount - coins[numCoins-1];
                with = dp[remaining][numCoins];
            }
            int without= dp[amount][numCoins-1]; // upto prev num of coins
            dp[amount][numCoins]=with+without;
        }
    }
    cout<<"BottomUp Table:"<<endl;
    for(int i=0;i<=sum;i++){
        cout<<i<<" : ";
        for(int j=0;j<=n;j++){
            cout<<dp[i][j]<<" ";
        }
        cout<<endl;
    }
    return dp[sum][n];
}
int main(){
    freopen("ip.txt","r",stdin);

    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        vector<int> coins(n);
        for(int i=0;i<n;i++){
            cin>>coins[i];
        }
        int sum;
        cin>>sum;
        cout<<"Memoization Logic 1: "<<coinChange1(sum,coins)<<endl;
        cout<<"Memoization Logic 2:"<<coinChange2(sum,coins)<<endl;
        cout<<"TopDown: "<<coinChangeTD(sum,coins)<<endl;
        cout<<"BottomUp: "<<coinChangeBU(sum,coins)<<endl;
    }
}