-1

I built the following coin change (C#) that works perfectly:

class Program
    {

        static int amount = 0;

        static void Main(string[] args)
        {

            EnterAmount();

            int[] coins = new int[] { 500, 100, 50, 20, 10, 5, 2, 1 };

            int Results = 0;

            for (int i = 0; i < coins.Length; i++)
            {
                    Results = amount / coins[i];
                    Console.WriteLine(Results + " x " + coins[i]);
                    amount -= Results * coins[i];
            }
        }

        static void EnterAmount()
        {
            Console.Out.WriteLine("Enter an amount : ");
            amount = int.Parse(Console.ReadLine());
        }
    }

My problem is that I don't know how to limit the quantity of coins for every coin. For exemple, I would like to have a maximum number of 4 coins of €500, 6 coins of €10, 5 coins of €2, etc. And it would be awesome that the coin change returns the number of coins used for every coin.

Can you help me please? Thank you.

shA.t
  • 16,580
  • 5
  • 54
  • 111
Benoda
  • 133
  • 1
  • 10
  • Make an int array of maximums and do min(Results, maxAmount[i]) * coins[i]. – Millie Smith Mar 07 '15 at 15:58
  • Also, rename `Results` to something more meaningful, like `currentCoinCount`, things might be a bit clearer. You might also consider using `amount %= coins[i];` instead of `amount -= Results * coins[i]` to make it clear that you're taking the remainder. – Paul Griffin Mar 07 '15 at 16:03
  • 3
    This is closely related to certain NP complete knapsack problems. – CodesInChaos Mar 07 '15 at 16:12
  • @CodesInChaos, I was just about to point that out... – Paul Griffin Mar 07 '15 at 16:16
  • I'm pretty sure that, unlike the more general problem with arbitrary values, the 1, 2, 5, 10 etc. pattern allows an efficient solution. I'm too lazy to search, but considering the popularity of the problem good explanations of such algorithms should be easy to find. – CodesInChaos Mar 07 '15 at 16:20
  • Specifically, I believe this is the Bounded Knapsack problem: http://www.codeproject.com/Articles/706838/Bounded-Knapsack-Algorithm – Paul Griffin Mar 07 '15 at 16:41

2 Answers2

1

Be aware that this code just answers your question about who to limit your coins number, but your algorithm is not complete as you don't consider a lot of corner cases.

static void Main(string[] args)
{
    var amount = 100000;

    var availabeCoins = new CoinPack[] 
    { 
        new CoinPack { Value = 500, Amount = 2 },
        new CoinPack { Value = 100, Amount = 3 },
        new CoinPack { Value = 50, Amount = 5 },
        new CoinPack { Value = 20, Amount = 1 },
        new CoinPack { Value = 10, Amount = 2 },
        new CoinPack { Value = 5, Amount = 0 },
        new CoinPack { Value = 2, Amount = 10 },
        new CoinPack { Value = 1, Amount = 500 }
    };

    var usedCoins = new CoinPack[] 
    { 
        new CoinPack { Value = 500 },
        new CoinPack { Value = 100 },
        new CoinPack { Value = 50 },
        new CoinPack { Value = 20 },
        new CoinPack { Value = 10 },
        new CoinPack { Value = 5 },
        new CoinPack { Value = 2 },
        new CoinPack { Value = 1 }
    };

    for (int i = 0; i < availabeCoins.Length; i++)
    {
        usedCoins[i].Amount = amount / availabeCoins[i].Value;
        if (usedCoins[i].Amount > availabeCoins[i].Amount)
        {
            usedCoins[i].Amount = availabeCoins[i].Amount;
        }

        amount -= usedCoins[i].Amount * usedCoins[i].Value;
    }

    foreach (var usedCoin in usedCoins)
    {
        Console.WriteLine(usedCoin.Value + " " + usedCoin.Amount);
    }
}

class CoinPack
{
    public int Value;
    public int Amount;
}

UPD This solution is pretty inefficient, but I guess it solves your problem. You can take it as a reference and improve it yourself.

void Main(string[] args)
{
    var amount = 6;

    var availabeCoins = new List<CoinPack>
    { 
        new CoinPack { Value = 500, Amount = 0 },
        new CoinPack { Value = 100, Amount = 0 },
        new CoinPack { Value = 50, Amount = 0 },
        new CoinPack { Value = 20, Amount = 0 },
        new CoinPack { Value = 10, Amount = 0 },
        new CoinPack { Value = 5, Amount = 1 },
        new CoinPack { Value = 2, Amount = 3 },
        new CoinPack { Value = 1, Amount = 0 }
    };

    var usedCoins = new List<CoinPack>
    { 
        new CoinPack { Value = 500, Amount = 0 },
        new CoinPack { Value = 100, Amount = 0 },
        new CoinPack { Value = 50, Amount = 0 },
        new CoinPack { Value = 20, Amount = 0 },
        new CoinPack { Value = 10, Amount = 0 },
        new CoinPack { Value = 5, Amount = 0 },
        new CoinPack { Value = 2, Amount = 0 },
        new CoinPack { Value = 1, Amount = 0 }
    };

    if (Change(amount, availabeCoins, usedCoins) != null)
    {
        foreach (var usedCoin in usedCoins)
        {
            Console.WriteLine(usedCoin.Value + " " + usedCoin.Amount);
        }
    }
    else
    {
        Console.WriteLine("Cannot find exact change");
    }
}

List<CoinPack> Change(int amount, List<CoinPack> availableCoins, List<CoinPack> usedCoins)
{
    if (amount == 0)
    {
        return availableCoins;
    }

    if (amount < 0)
    {
        return null;
    }

    foreach (var availableCoin in availableCoins.Where(ac => ac.Amount > 0 && amount >= ac.Value))
    {
        var newAvailableCoins = CopyCoins(availableCoins);
        newAvailableCoins.First(c => c.Value == availableCoin.Value).Amount--;
        var change = Change(amount - availableCoin.Value, newAvailableCoins, usedCoins);

        if (change == newAvailableCoins)
        {
            usedCoins.First(c => c.Value == availableCoin.Value).Amount++;
            return availableCoins;
        }
    }

    return null;
}

List<CoinPack> CopyCoins(List<CoinPack> coinPacks)
{
    var copy = new List<CoinPack>();
    foreach (var coinPack in coinPacks)
    {
        copy.Add(new CoinPack { Value = coinPack.Value, Amount = coinPack.Amount });
    }
    return copy;
}

class CoinPack
{
    public int Value;
    public int Amount;
}
aush
  • 2,108
  • 1
  • 14
  • 24
  • A simple greedy algorithm like this doesn't work. Try it with amount = 6 while having 1 coin with value 5 and 3 coins with value 2. – CodesInChaos Mar 07 '15 at 16:06
  • 1
    @CodesInChaos, I know. Op's algorithm is not complete, I'm just answering his question, not developing an algorithm for him. – aush Mar 07 '15 at 16:08
  • I assume that the OP wants to *solve* the problem with limited coins. This "answer" only handles the most trivial aspect of that and is not helpful. – CodesInChaos Mar 07 '15 at 16:24
0

I think this will be helpfull:

using System;
using System.Data;
using System.IO;

namespace ConsoleApplicationTests
{
    class Program
    {
        static int amount = 321370;

        static void Main(string[] args)
        {
            Coin[] c = new Coin[] { new Coin(500, 7), new Coin(200, 3), new Coin(100, 5) ,
                                    new Coin(50, 6), new Coin(20, 2), new Coin(10, 4),
                                    new Coin(5, 0), new Coin(2, 5), new Coin(1, 3)};
            int netAmount = amount;

            for (int i = 0; i < c.Length; i++)
            {
                amount -= c[i].coveredPrice(amount);
            }

            for (int i = 0; i < c.Length; i++)
            {
                Console.WriteLine(c[i].ToString());
            }

            Console.ReadLine();

        }
    }

    class Coin
    {
        private int price;
        private int counted;    // You can continue your bank for next amount too.
        private int maxNo;

        public Coin(int coinPrice, int coinMaxNo)
        {
            this.price = coinPrice;
            this.maxNo = coinMaxNo;
            this.counted = 0;
        }

        public int coveredPrice(int Price)
        {
            int Num = Price / price;
            if (maxNo == 0)
                return 0;
            if (maxNo != -1)             //-i is infinit
                if (Num > this.maxNo - this.counted)
                    Num = maxNo;
            this.counted += Num;
            return Num * price;
        }

        //public int getPrice() { return this.price; }
        //public int getCount() { return this.counted; }
        //public int getMax() { return this.maxNo; }
        public override string ToString()
        {
            return string.Format("{0} x {1} (max {2}) ", this.price.ToString(), this.counted.ToString(), this.maxNo.ToString());
        }
    }
}
shA.t
  • 16,580
  • 5
  • 54
  • 111
  • For showing net add `Console.WriteLine("Net is " + amount.ToString());` after writing results ... – shA.t Mar 07 '15 at 16:44