Кратчайший путь от одного источника, который проходит через N ребер - PullRequest
0 голосов
/ 29 июня 2018

В своем экономическом исследовании я в настоящее время имею дело с конкретной проблемой кратчайшего пути:

Учитывая направленный детерминированный динамический граф с весами по краям, мне нужно найти кратчайший путь от одного источника S, который проходит через N ребер. Граф может иметь циклы, вес ребер может быть отрицательным, и путь может проходить через вершину или ребро более одного раза.

Есть ли эффективный алгоритм для этой проблемы?

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Ограничение «ровно N ребер» значительно облегчает решение этой проблемы, чем если бы этого ограничения не существовало. По сути, вы можете решить N = 0 (только начальный узел), использовать его для решения N = 1 (все соседи начального узла), затем N = 2 (соседи решения с N = 1, выбирая путь с наименьшей стоимостью для узлов, которые связаны с несколькими узлами) и т. д.

В псевдокоде (используя {field: val} для обозначения «записи с полем с именем field со значением val»):

# returns a map from node to cost, where each key represents 
# a node reachable from start_node in exactly n steps, and the
# associated value is the total cost of the cheapest path to 
# that node
cheapest_path(n, start_node):
  i = 0
  horizon = new map()
  horizon[start_node] = {cost: 0, path: []}
  while i <= n:
    next_horizon = new map()
    for node, entry in key_value_pairs(horizon):
      for neighbor in neighbors(node):
        this_neighbor_cost = entry.cost + edge_weight(node, neighbor, i)
        this_neighbor_path = entry.path + [neighbor]
        if next_horizon[neighbor] does not exist or this_neighbor_cost < next_horizon[neighbor].cost:
          next_horizon[neighbor] = {cost: this_neighbor_cost, path: this_neighbor_path}
    i = i + 1
    horizon = next_horizon
  return horizon

Мы учитываем динамические веса, используя edge_weight(node, neighbor, i), что означает «стоимость перехода от node до neighbor на шаге времени i.

Это вырожденная версия алгоритма кратчайшего пути из одного источника, такого как алгоритм Дейкстры, но он намного проще, потому что мы знаем, что должны пройти ровно N шагов, поэтому нам не нужно беспокоиться о застревании в циклах с отрицательным весом или более длинные пути с более дешевыми весами, или что-нибудь в этом роде.

0 голосов
/ 29 июня 2018

Одна возможность будет:

Сначала найдите самый низкий вес ребра на графике.

И затем построить очередь приоритетов всех путей от начального ребра (изначально пустой путь от начальной точки), где все ребра, которые еще предстоит обработать, считаются имеющими наименьший вес.

Основной цикл:

  1. Удалить путь с наименьшим весом из очереди.
  2. Если путь имеет N ребер, все готово
  3. В противном случае добавить все возможные односторонние расширения этого пути в приоритетную очередь

Однако, у этого простого алгоритма есть недостаток - вы можете повторно посетить вершину несколько раз, как i-й край (посещение 2-го и 4-го - это нормально, но проблема 4-го в двух разных путях), что неэффективно.

Алгоритм можно улучшить, пропустив их на 3-м шаге выше, поскольку очередь с приоритетами гарантирует, что первый частичный путь к вершине имел наименьшую весовую сумму к этой вершине, а остальная часть пути не зависит от как вы достигли вершины (поскольку ребра и вершины могут быть дублированы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...