老实说,这似乎不是一个图形类型问题,因为它是一个组合/算法类型问题 - 但我不知道如何标题。
情况是这样的:我有一个节点集合,它是我的无向图的所有节点的子集。假设我的图由节点[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)....等,我想找到一组最小的边,可用于在任意两对端节点之间形成这些路径中的至少一个。因此,可能是这个最小集合需要集合的节点之间的每个边缘,但也可能是它需要比这少得多的情况。
我知道,这是很多东西。这似乎很难。我的大脑告诉我这是一个集合的交叉问题,可能没有一个简单的答案,但我知道我需要帮助甚至接近它。
答案 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