/// <summary> /// Поиск оптимального маршрута с посещением всех веток метро с помощью метода ветвей и границ /// </summary> /// <param name="scheme"></param> /// <returns></returns> public IEnumerable <IRoute> VisitAllLinesByBranchAndBound(Scheme scheme) { if (scheme == null) { throw new ArgumentNullException(); } var stations = scheme.GetAllLineRelationStations(); // Все пересадочные станции всех веток var lines = scheme.GetLines().ToArray(); // все ветки метро var linesStations = new Station[lines.Length][]; // массив станций переходов для каждой ветки var indeces = new int[lines.Length]; // индекс станции для каждой ветки for (var i = 0; i < lines.Length; ++i) { linesStations[i] = lines[i].GetRelationStations().ToArray(); indeces[i] = 0; } var lastLineInd = indeces.Length - 1; var cache = new RoutesCollection <Station>((r) => new TwoItemsKey <Station>(r.From, r.To)); var visitor = new AllLinesVisitor(); int counter = 0; int skipped = 0; bool next = true; do { // Обработка станций var routes = new List <IRoute>(); for (int fromLineId = 0; fromLineId < indeces.Length - 1; ++fromLineId) { var fromStation = linesStations[fromLineId][indeces[fromLineId]]; for (int toLineId = fromLineId + 1; toLineId < indeces.Length; ++toLineId) { var toStation = linesStations[toLineId][indeces[toLineId]]; IRoute route; if (!cache.TryGetRoute(fromStation, toStation, out route)) { route = FindRoute(fromStation, toStation); cache.Add(route); } routes.Add(route); } } visitor.Push(routes); counter++; /* * // ограничение маршрутов для тестирования * if (counter > 10) * next = false; */ // Переход к следующей комбинации var lineInd = lastLineInd; do { ++indeces[lineInd]; if (indeces[lineInd] >= linesStations[lineInd].Length) { if (lineInd == 0) { // перебраны все возможные комбинации next = false; break; } else { indeces[lineInd] = 0; } } else { break; } --lineInd; }while (lineInd >= 0); }while (next); visitor.Complete(); visitor.Completion.Wait(); return(visitor.GetResults()); }
/// <summary> /// Поиск оптимальных маршрутов движения для посещения всех веток метро /// </summary> /// <param name="scheme">Схема метро</param> /// <returns>Наиболее быстрые маршруты</returns> public IEnumerable <IRoute> VisitAllLines(Scheme scheme) { if (scheme == null) { throw new ArgumentNullException(); } var stations = scheme.GetAllLineRelationStations().ToList(); // Все пересадочные станции всех веток LineRoutesCollection linesRoutes = new LineRoutesCollection(); // Маршруты между линиями PartialRoutesCollection routes = new PartialRoutesCollection(); // Маршруты, которые могут стать решением // Построение маршрутов между всеми парами пересадочных станций for (int i = 0; i < stations.Count - 1; ++i) { var s1 = stations[i]; for (int j = i + 1; j < stations.Count; ++j) { var s2 = stations[j]; // Поиск маршрута только если станции на разных ветках // и маршрут не был ранее уже найден if (s1.Line != s2.Line && !linesRoutes.ContainsRoute(s1, s2)) { var newRoute = FindRoute(s1, s2); if (linesRoutes.Add(newRoute)) { routes.Add(newRoute); } } } } ResultCollection result = new ResultCollection(); while (routes.TryPop(out var route)) { if (route.Timespan > result.Timespan) { continue; } var targetLines = scheme.GetLinesExclude(route.GetLines()); // Ветки, которые еще осталось посетить if (targetLines.FirstOrDefault() == null) { result.Add(route); } else if (route.Timespan < result.Timespan) { // Время текущего маршрута меньше времени уже найденных полных маршрутов foreach (var targetLine in targetLines) { foreach (var additionalRoute in linesRoutes.GetRoutes(route.To, targetLine)) { // Дальше обрабатываются только те маршруты, которые короче уже найденных if (result.Timespan >= additionalRoute.Timespan + route.Timespan) { var newRoute = Route.Union(route, additionalRoute); routes.Add(newRoute); } } } } } return(result); }