Прогулка по дереву предварительного заказа минимального остовного дерева, сгенерированного алгоритмом Прима

Я пытаюсь реализовать приблизительный алгоритм для решения задачи коммивояжера (TSP), который можно использовать, когда неравенство треугольника выполняется для весов ребер. Как описано в Cormen et al., Introduction to Algorithms (3rd 3d.), псевдокод выглядит следующим образом:

введите здесь описание изображения

и вот пример:

введите здесь описание изображения

Я борюсь с тем, как реализовать обход дерева предварительного заказа по дереву, сгенерированному алгоритмом Прима. Поскольку это не бинарное дерево поиска, псевдокод, приведенный на странице https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2 кажется неприменимым.

Вместо атрибутов left и right узлы имеют атрибуты key и parent. Вот как они генерируются в моей реализации алгоритма Прима (с небольшим тестовым примером):

import math
import copy
import pytest
import pandas as pd
from cached_property import cached_property


class Node(object):
    def __init__(self, key=math.inf, parent=None):
        self.key = key
        self.parent = parent

    def __lt__(self, other):
        return self.key < other.key


class Graph(object):
    def __init__(self, edges):
        self.edges = edges

    @cached_property
    def nodes(self):
        _nodes = set()
        for edge in self.edges:
            _nodes.add(edge[0])
            _nodes.add(edge[1])
        return {node: Node() for node in list(_nodes)}

    @cached_property
    def adj(self):
        A = {node: [] for node in self.nodes}
        for edge in self.edges:
            u, v, _ = edge
            A[u].append(v)
            A[v].append(u)
        return A

    @cached_property
    def w(self):
        N = len(self.nodes)
        none_array = [[None for _ in range(N)] for _ in range(N)]
        df = pd.DataFrame(none_array, index=sorted(self.nodes), columns=sorted(self.nodes))
        for edge in self.edges:
            u, v, weight = edge
            df.set_value(u, v, weight)
            df.set_value(v, u, weight)
        return df

    def mst_prim(self, root):
        r = self.nodes[root]
        r.key = 0
        Q = copy.copy(self.nodes)
        while Q:
            u = min(Q, key=Q.get)
            u_node = Q.pop(u)
            for v in self.adj[u]:
                if v in Q and self.w[u][v] < self.nodes[v].key:
                    self.nodes[v].parent = u
                    self.nodes[v].key = self.w[u][v]


@pytest.fixture
def edges_simple():
    return [('a', 'b', 4),
            ('a', 'h', 8),
            ('b', 'h', 11),
            ('h', 'i', 7),
            ('b', 'c', 8),
            ('h', 'g', 1),
            ('i', 'c', 2),
            ('i', 'g', 6),
            ('c', 'd', 7),
            ('g', 'f', 2),
            ('c', 'f', 4),
            ('d', 'f', 14),
            ('d', 'e', 9),
            ('f', 'e', 10)
            ]

def test_mst_prim(edges_simple):
    graph = Graph(edges_simple)
    graph.mst_prim(root='a')
    # print("\n")
    # for u, node in graph.nodes.items():
    #   print(u, node.__dict__)
    assert graph.nodes['a'].parent is None
    assert graph.nodes['i'].parent == 'c'
    assert graph.nodes['d'].parent == 'c'



if __name__ == "__main__":
    # pytest.main([__file__+"::test_mst_prim", "-s"])
    pytest.main([__file__, "-s"])

Как я могу выполнить обход дерева предварительного порядка на этом графе? (Обратите внимание, что этот вопрос аналогичен предварительному обходу минимального охвата tree, но я нашел ответ, данный там довольно высокоуровневый).


person Kurt Peek    schedule 20.09.2017    source источник


Ответы (2)


Я предлагаю вам добавить новый список в ваш класс Node, например, с именем children.

После вашего алгоритма Prim's вы можете просмотреть полученные узлы и добавить их к родительским children. Сложность O(n), так что ничего страшного. После этого обход DFS будет легким.

Но опять же, как и в упомянутом вами сообщении, у вас есть выбрать порядок для ваших детей для preorder обхода. В вашем случае, когда у вас есть ссылка только на ваш parent, нет возможности узнать, например, что такое дочерний элемент left-most.

person Schidu Luca    schedule 20.09.2017

Я немного озадачен тем, почему алгоритм в книге Кормена упоминает обход предварительного порядка, поскольку среди «потомков» узла в минимальном остовном дереве MST нет порядка.

Насколько я понимаю, вам просто нужно выполнить поиск в глубину (DFS) на MST, как указано здесь и здесь. Это означает, что если вы находитесь на узле u, вы посещаете одного из его соседей или «потомков» в произвольном порядке.

Вы можете реализовать DFS, используя представление списка смежности графа, который обозначен как adj в вашем классе.

person Flatfoot    schedule 20.09.2017