Учитывая граф, который вершины 3 цветов, найти кратчайший путь со следующими кодировками - PullRequest
0 голосов
/ 15 апреля 2019

Учитывая неориентированный граф G, где каждая вершина окрашена зеленым красным или синим и положительными весами, найдите кратчайший путь, заканчивающийся в узле T,со следующими условиями:

1.можно использовать вершину зеленого цвета, только если я прошел вершину красного цвета на пути.

2.можно использовать вершину синего цвета, только если я прошел вершинукрасный цвет и вершина зеленого цвета в пути.

Я попытался использовать DFS и найти возможные пути, а затем запустить алгоритм Дейкстры из узла T в возможных путях, но сложность была слишком высокой.Спасибо!

1 Ответ

0 голосов
/ 15 апреля 2019

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

def red__and_green_dijkstra(G, origin, dest):
    for node in G.nodes():
        node.was_visited_R = False
        node.was_visited_RG = False
    origin.was_visited_R = True
    origin.was_visited_RG = True
    Q = empty_priority_queue()
    for neighbor in origin.neighbors():
        if neighbor.color == red:
            Q.push((weight(origin, neighbor), neighbor, [origin, neighbor], False))
        if neighbor.color == green and origin.color == red:
            Q.push((weight(origin, neighbor), neighbor, [origin, neighbor], True))
    while not Q.is_empty():
        dist, node, path, can_pick_blue = Q.pop()
        node.was_visited_R = True  # mark the node as visited with a 'red' path
        if can_pick_blue:
            node.was_visited_RG = True  # mark the node as visited on a 'red and green' path
        if node == dest:
            return path
        for neighbor in node.neighbors():
            if can_pick_blue:  # met at least 1 green node on path so far
                if neighbor.color == red and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
                if neighbor.color == green and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
                if neighbor.color == blue and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
            else:  # only red nodes on path so far
                if neighbor.color == red and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], False))
                if neighbor.color == green and not neighbor.was_visited_RG:
                    Q.push(dist + (weight(node, neighbor), neighbor, path + [neighbor], True))
  1. Расстояние до источника: мы также используем его в качестве значения, по которому приоритет отдается в очереди (мы pop() узлы с наименьшими расстояниями)
  2. текущий узел
  3. весь путь: поскольку вам нужен путь (а не только расстояние), вам также необходимо сохранить его в своей очереди
  4. логическое значение can_pick_blue. Поскольку очередь была инициализирована красными узлами, мы уверены, что можем выбрать зеленый узел. Но для синих узлов мы должны быть уверены, что в пути есть хотя бы один зеленый и один красный узел. Это логическое значение отслеживает эту информацию. Можно было бы проверить все узлы на пути, но это было бы дороже.

Для инициализации нам нужно выделить 2 случая:

  • если источник красного цвета, мы можем начать использовать красные и зеленые узлы, поскольку в пути уже есть красный узел.
  • Если источник не красный, то мы должны выбрать красный узел.

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

Сложность этого алгоритма такая же, как и у Дейкстры, O(n.log n).

Редактировать : Чтобы получить правильные результаты, я добавил второе логическое значение, чтобы пометить узел как посещенный. В самом деле, вам нужно два из них: один, чтобы узнать, был ли узел посещен на пути «только красный», где выбор синего цвета запрещен, и один, чтобы узнать, был ли узел посещен на «красном и зеленом» (и в конечном итоге синий) путь, по которому также можно выбрать синие узлы.
Фактически требуется иметь возможность выбирать все соответствующие пути и отбрасывать лишние.

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