static double MinCostForAcquiring(IEnumerable<Product> productsToBuy, Purchase startingPoint, IEnumerable<Location> locations, double gasPrice, IDictionary<string, double> memoizer) { if (!productsToBuy.Any()) { return startingPoint.Location.DistanceTo(locations.GetHome()) * gasPrice; } string _key = string.Format("{0}:{1}:{2}", startingPoint.Location.Name, startingPoint.IsPerishable.ToString(), productsToBuy.Select(p => p.Name).Aggregate((r, n) => r + ";" + n)); if (memoizer.ContainsKey(_key)) { return memoizer[_key]; } var _result = productsToBuy.SelectMany(p => startingPoint.PossiblePurchasesOf(p, locations, gasPrice) .Select(pur => pur.Cost + MinCostForAcquiring(productsToBuy.Without(p), pur, locations, gasPrice, memoizer))) .Min(); memoizer.Add(_key, _result); return _result; }
private IEnumerable<Purchase> AllPossiblePurchases(IEnumerable<Location> locations, double gasPrice) { if (_purchaseCache == null) { _purchaseCache = locations.SelectMany(loc => loc.Products.Select(p => new Purchase() { Location = loc, Product = p, IsPerishable = this.IsPerishable & this.Location.IsSameAs(loc) ? true : p.IsPerishable, Cost = this.IsPerishable & loc.Name != this.Location.Name ? p.Price + this.Location.DistanceToVia(loc, locations.GetHome()) * gasPrice : p.Price + (this.Location.DistanceTo(loc) * gasPrice) }) ); } return _purchaseCache; }