所有节点对之间简单路径的最小边缘表示

时间:2018-03-30 16:22:53

标签: algorithm graph set traversal combinatorics

老实说,这似乎不是一个图形类型问题,因为它是一个组合/算法类型问题 - 但我不知道如何标题。

情况是这样的:我有一个节点集合,它是我的无向图的所有节点的子集。假设我的图由节点[0..20]组成。我的节点集合是[0,1,2,3,4,5]。

我的图表不完整,我们不知道算法运行之前它有什么边缘。

我正在做的是找到遍历集合中所有节点的所有简单路径,但路径必须从具有集合边缘 out 的节点开始,并且在具有集合的边缘 out 的节点处结束。

根据我的集合的节点有多少边缘到集合中的每个其他节点,我可能最终会有许多连接到两个相同端节点的路径。 (0,1,2,3,4,5),(0,2,3,1,4,5),(0,3,4,2,1,5)......等

我想做的是,给出了每个端节点的路径集合..(0,1),(1,3),(2,4),( 0,4),(2,5)....等,我想找到一组最小的边,可用于在任意两对端节点之间形成这些路径中的至少一个。因此,可能是这个最小集合需要集合的节点之间的每个边缘,但也可能是它需要比这少得多的情况。

我知道,这是很多东西。这似乎很难。我的大脑告诉我这是一个集合的交叉问题,可能没有一个简单的答案,但我知道我需要帮助甚至接近它。

1 个答案:

答案 0 :(得分:0)

我认为您要求的内容被称为minimum spanning tree给定图表。

[简单生成树算法的删除说明]

更新每次OP澄清

对于图中的每对节点,我们需要至少包含一个路径,其中包含每个节点,而不会再次访问任何节点。这是Hamiltonian path

我同意这是一个集驱动的问题:每对节点都有一组相关的哈密尔顿路径(HP)。每个路径由一系列边缘定义。我们可以将它们表示为边的:我们需要所有的边来形成路径,所以顺序并不重要。

如果单调乏味,找到所有汉密尔顿路径都是相对容易的。

在给定一组节点all,一组起始节点s和一组结束节点e的情况下,编写递归例程以查找所有HP。我不认为这是多项式时间;充其量,我认为它是len(e)!。然而,memoizing(动态编程)应该能够将其简化为易处理的东西,也许是多项式。

function find_paths(all, s, e)
    paths = <empty>
    if |all| == 2   // base case: no intermediate nodes
        for (start, end) in s x e
            if (start, end) has an edge
                add that edge to paths

    else if |all| == 3  // base case: only one intermediate node
        inter = all - start - end  // identify the remaining node
        for (start, end) in s x e
            if (start, inter) and (inter, end) have edges
                add that edge pair to paths

    else // recursion case
         // for each (start, end) pair, remove those from the graph,
         //   and find all intermediate paths in the remaining nodes.
        for (start, end) in s x e
            all_prime = all - start - end
            s_prime = all nodes with an edge to start
            e_prime = all nodes with an edge to end
            hp_prime = find_paths(all_prime, s_prime, e_prime)
            for each inner_path in hp_prime
                // grab the endpoints; link them to (start, end)
                path_start = inner_path[0][0]
                path_end   = inner_path[len(inner_path)-1][1]
                add ((start, path_start), inner_path, (path_end, end)) to path
        return path

使用每对节点调用此方法,获取图中的所有哈密尔顿路径,由节点对索引。将每条路径缩减为一组边。例如,使用eij(使用ii和j时,四度完全连接的图形现在看起来像这样。

(0, 1) [{e02, e23, e13}, {e03, e23, e12})
(0, 2) [{e01, e13, e23}, {e03, e13, e12})
...
(2, 3) [{e12, e01, e03}, {e02, e01, e13})

现在,要找到更小的树,请以您喜欢的任何方式优先清除边缘。要获得最佳解决方案,请通过递归尝试所有|E|!个订单。从这里开始,它又简单但又乏味

if any node-pair has no path, FAIL
put all edges into the priority_list
iterate through the node-pair sets
    if any pair has only one set (path),
        remove all the edges in that path from priority_list
prioritize the list in any fashion desired
while priority_list isn't empty
    victim = priority_list.pop()
    remove each path including victim.
    if this results in a node-pair's list having only one remaining path,
        remove all edges in that path from the priority_list

return the remaining priority_list as a sort-of-minimal set