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; }
static void Main(string[] args) { string _inputFile = args[0]; string _outputFile = Path.ChangeExtension(_inputFile, "out"); var _start = DateTime.Now; using (var _input = new StreamReader(_inputFile)) { using (var _output = new StreamWriter(_outputFile)) { var _testCases = _input.ReadLine(); string _line; int _case = 0; while((_line = _input.ReadLine()) != null) { ++_case; var _parts = _line.Split(' '); var _numOfProducts = int.Parse(_parts[0]); var _numOfShops = int.Parse(_parts[1]); var _gasPrice = double.Parse(_parts[2]); IEnumerable<Product> _products = _input.ReadLine().Split(' ').Select(s => new Product(s)); var _locations = new List<Location>(); var _home = new Location("home", 0, 0); _locations.Add(_home); Enumerable.Range(1, _numOfShops).ToList().ForEach(x => { _parts = _input.ReadLine().Split(' '); var _loc = new Location(string.Format("{0}.{1}", _case, x.ToString()), int.Parse(_parts[0]), int.Parse(_parts[1])); _loc.Products = _parts.Skip(2).Select(s => { var _a = s.Split(':'); return _products.GetByName(_a[0]).Clone(double.Parse(_a[1])); }); _locations.Add(_loc); }); var _firstOne = new Purchase() { Location = _locations.GetHome(), Cost=0.0, IsPerishable=false, Product=null}; var _memoizer = new Dictionary<string, double>(); Console.WriteLine(string.Format("Calculating Case # {0}...", _case)); var _minAmount = MinCostForAcquiring(_products, _firstOne, _locations, _gasPrice, _memoizer); Console.WriteLine(string.Format("Done...result={0}", _minAmount)); Console.WriteLine(); _output.WriteLine(string.Format("Case #{0}: {1}", _case, Math.Round(_minAmount, 7).ToString("F7", new CultureInfo("en-US")))); } } } Console.WriteLine(string.Format("Duration: {0}", DateTime.Now.Subtract(_start).ToString())); Console.ReadLine(); }