public decimal CalculateTotal(Trolley trolley)
        {
            var purchaseCosts = trolley.Purchases.Select(purchase =>
            {
                var pricingList = GetPricingList(trolley, purchase.Name);

                // Initial State
                var possibleTotals             = new List <decimal>();
                var lowestPriceQuantitiesSoFar = new Dictionary <int, decimal>();

                var subtotals = new List <QuantityPrice>();
                subtotals.Add(new QuantityPrice(purchase.Quantity, 0));
                var newSubtotals = new List <QuantityPrice>();

                while (subtotals.Count > 0)
                {
                    // Map
                    foreach (var priceQuantity in pricingList)
                    {
                        var nextSubtotals = subtotals.Select(subtotal => new QuantityPrice(subtotal.Quantity - priceQuantity.Key, subtotal.Price + priceQuantity.Value));
                        newSubtotals.AddRange(nextSubtotals);
                    }
                    ;

                    // Reduce
                    possibleTotals.AddRange(newSubtotals.Where(ns => ns.Quantity == 0).Select(ns => ns.Price));
                    newSubtotals.RemoveAll(ns => ns.Quantity <= 0);
                    newSubtotals = newSubtotals.GroupBy(ns => ns.Quantity, (key, result) => new QuantityPrice(key, result.Select(r => r.Price).Min())).ToList();

                    // Increment
                    subtotals    = newSubtotals;
                    newSubtotals = new List <QuantityPrice>();
                }

                return(possibleTotals.Min());
            });

            return(purchaseCosts.Sum());
        }
        public Dictionary <int, decimal> GetPricingList(Trolley trolley, string productName)
        {
            var discounts = trolley.Discounts.Where(s => s.Name == productName);
            var product   = trolley.Products.Single(p => p.Name == productName);

            var pricingList = new Dictionary <int, decimal>();

            pricingList.Add(1, product.Price);

            foreach (var discount in discounts)
            {
                if (pricingList.ContainsKey(discount.Quantity))
                {
                    pricingList[discount.Quantity] = Math.Min(discount.Price, pricingList[discount.Quantity]);
                }
                else
                {
                    pricingList.Add(discount.Quantity, discount.Price);
                }
            }

            return(pricingList);
        }