예제 #1
0
        public int NumberOfAdditionalSantas()
        {
            var additionalSantaIds = NonEmptyRoutes.Where(r => OptimizationInput.IsAdditionalSanta(r.SantaId))
                                     .Select(r => r.SantaId)
                                     .Distinct().ToList();

            return(additionalSantaIds.Count);
        }
예제 #2
0
        public int AdditionalSantaWorkTime()
        {
            var additionalSantaIds = NonEmptyRoutes.Where(r => OptimizationInput.IsAdditionalSanta(r.SantaId))
                                     .Select(r => r.SantaId)
                                     .Distinct().ToList();
            var additionalSantaRoutes = NonEmptyRoutes.Where(r => additionalSantaIds.Contains(r.SantaId));

            return(additionalSantaRoutes.Select(r =>
                                                r.Waypoints.Max(wp => wp.StartTime) - r.Waypoints.Min(wp => wp.StartTime))
                   .Sum());
        }
예제 #3
0
        public virtual int NumberOfMissingBreaks()
        {
            var santaBreaks = new Dictionary <int, int>();

            foreach (var v in OptimizationInput.Visits.Where(v => v.IsBreak))
            {
                if (santaBreaks.ContainsKey(v.SantaId))
                {
                    throw new InvalidOperationException("each santa can only have at most one break");
                }
                santaBreaks.Add(v.SantaId, v.Id);
            }

            return(NonEmptyRoutes.Count(r => santaBreaks.ContainsKey(r.SantaId) &&
                                        r.Waypoints.All(wp => wp.VisitId != santaBreaks[r.SantaId])));
        }
예제 #4
0
        public virtual int NumberOfNotVisitedFamilies()
        {
            var visitedVisits = NonEmptyRoutes.SelectMany(r => r.Waypoints.Select(w => w.VisitId));

            return(OptimizationInput.Visits.Count(v => !v.IsBreak && !visitedVisits.Contains(v.Id)));
        }
예제 #5
0
        /// <summary>
        /// Returns null if this OptimizationResult is valid.
        /// Otherwise, returns an error message.
        /// This function returns immediately if anything invalid is found.
        /// </summary>
        /// <returns></returns>
        public string Validate()
        {
            List <Route> routes = NonEmptyRoutes.ToList();

            // check santa is only used once per day
            {
                var multipleUses = routes.GroupBy(r => (r.SantaId, FindDay(r))).Where(g => g.Count() > 1).ToList();
                if (multipleUses.Count > 0)
                {
                    return($"Santa {multipleUses.First().Key} is used more than once on the same day.");
                }
            }

            // validate starts
            {
                var wrongRoutes = routes.Where(r => r.Waypoints.First().VisitId != Constants.VisitIdHome).ToList();
                if (wrongRoutes.Count > 0)
                {
                    var(from, to) = FindDay(wrongRoutes.First());
                    return($"Wrong start in route of santa {wrongRoutes.First().SantaId} on day {from}-{to}.");
                }
            }

            // validate ends
            {
                var wrongRoutes = routes.Where(r => r.Waypoints.Last().VisitId != Constants.VisitIdHome).ToList();
                if (wrongRoutes.Count > 0)
                {
                    var(from, to) = FindDay(wrongRoutes.First());
                    return($"Wrong end in route of santa {wrongRoutes.First().SantaId} on day {from}-{to}.");
                }
            }

            // check way from home to first visit
            {
                var wrongStartWays = routes.Where(r =>
                {
                    var visit = r.Waypoints.ElementAt(1);
                    return(OptimizationInput.Visits[visit.VisitId].WayCostFromHome > visit.StartTime - r.Waypoints.First().StartTime);
                }).ToList();
                if (wrongStartWays.Count > 0)
                {
                    return($"Way between home and visit {wrongStartWays.First().Waypoints.ElementAt(1).VisitId} is too short.");
                }
            }

            // check way from last visit to home
            {
                var wrongEndWays = routes.Where(r =>
                {
                    var lastVisit = r.Waypoints.ElementAt(r.Waypoints.Length - 2);
                    return(OptimizationInput.Visits[lastVisit.VisitId].WayCostToHome > r.Waypoints.Last().StartTime - (lastVisit.StartTime + OptimizationInput.Visits[lastVisit.VisitId].Duration));
                }).ToList();
                if (wrongEndWays.Count > 0)
                {
                    return($"Way between visit {wrongEndWays.First().Waypoints.Reverse().Skip(1).First().VisitId} and home is too short.");
                }
            }

            // check ways in between
            {
                foreach (var route in routes)
                {
                    var middleWaypoints = route.Waypoints.Take(route.Waypoints.Length - 1).Skip(1).ToList();
                    var previous        = middleWaypoints.First();
                    foreach (var current in middleWaypoints.Skip(1))
                    {
                        if (OptimizationInput.RouteCosts[previous.VisitId, current.VisitId] > current.StartTime - (previous.StartTime + OptimizationInput.Visits[previous.VisitId].Duration))
                        {
                            return($"Way between visit {previous.VisitId} and visit {current.VisitId} is too short.");
                        }
                        previous = current;
                    }
                }
            }

            // valid
            return(null);
        }
예제 #6
0
        public int TotalVisitTime()
        {
            var visitedVisits = NonEmptyRoutes.SelectMany(r => r.Waypoints.Select(w => w.VisitId));

            return(OptimizationInput.Visits.Where(v => visitedVisits.Contains(v.Id)).Select(v => v.Duration).Sum());
        }
예제 #7
0
        public int TotalWayTime()
        {
            int totalTime = NonEmptyRoutes.Select(r => r.Waypoints.Last().StartTime - r.Waypoints[0].StartTime).Sum();

            return(totalTime - TotalVisitTime());
        }
예제 #8
0
 public int NumberOfRoutes()
 {
     return(NonEmptyRoutes.Count());
 }
예제 #9
0
 public int NumberOfNeededSantas()
 {
     return(NonEmptyRoutes.Select(FindDay).GroupBy(d => d).Select(g => g.Count()).Append(0).Max());
 }
예제 #10
0
 public int LongestDay()
 {
     return(NonEmptyRoutes.Select(r => r.Waypoints.Max(wp => wp.StartTime) - r.Waypoints.Min(wp => wp.StartTime)).Append(0).Max());
 }
예제 #11
0
 public int SantaWorkTime()
 {
     return(NonEmptyRoutes.Select(r => r.Waypoints.Max(wp => wp.StartTime) - r.Waypoints.Min(wp => wp.StartTime)).Sum());
 }