对于图形中的每个顶点,找到距离d内的所有顶点

时间:2011-04-16 08:18:07

标签: algorithm graph path shortest

在我的特定情况下,图表被表示为邻接列表,并且是无向和稀疏的,n可以是数百万,d是3.计算A ^ d(其中A是邻接矩阵)并挑选出非零条目有效,但我想要一些不涉及矩阵乘法的东西。对每个顶点进行广度优先搜索也是一种选择,但速度很慢。

4 个答案:

答案 0 :(得分:1)

def find_d(graph, start, st, d=0):

    if d == 0:
        st.add(start)
    else:
        st.add(start)
        for edge in graph[start]:
            find_d(graph, edge, st, d-1)

    return st

graph = { 1 : [2, 3],
      2 : [1, 4, 5, 6],
      3 : [1, 4],
      4 : [2, 3, 5],
      5 : [2, 4, 6],
      6 : [2, 5]
    }

print find_d(graph, 1, set(), 2)

答案 1 :(得分:0)

假设我们有一个函数verticesWithin(d,x),可以找到顶点d距离x内的所有顶点。

这个问题的一个好策略是揭示缓存/记忆机会,就是问一个问题:这个问题的子问题如何相互关联?

在这种情况下,我们可以看到verticesWithin(d,x) d >= 1 vertices(d-1,y[i])是范围内所有i y=verticesWithin(1,x)的联合,d == 0。如果{x}则只是d == 1。 (我假设一个顶点被认为与自身的距离为0。)

实际上,您需要查看案例x的邻接列表,而不是使用该关系,以避免无限循环。您还希望避免将y本身视为verticesWithin(d,x)成员的冗余。

此外,如果d的返回类型从简单列表或集合更改为x集合列表,表示距verticesWithin(d,x) = init(verticesWithin(d+1,x))的距离越来越远,则

init

其中verticesWithin是产生列表中除最后一个元素之外的所有元素的函数。显然,如果将字面转换为代码,这将是一个非终止的递归关系,所以你必须对你如何实现它有点聪明。

配备子问题之间的这些关系,我们现在可以缓存{{1}}的结果,并使用这些缓存的结果来避免执行冗余遍历(虽然以执行某些设置操作为代价 - 我并非完全确定这是一场胜利)。我将把它作为练习来填写实施细节。

答案 2 :(得分:0)

您已经提到了计算A^d的选项,但这远远超出您的需要(正如您已经说过的那样)。

然而,有一种更便宜的方式来使用这个想法。假设您有一个零(1)的零(1)}向量v,表示一组顶点。向量w := A v现在在每个节点都有一个,只需一步即可从起始节点到达。迭代,u := A w对于您可以在两个步骤中从起始节点到达的每个节点都有一个,等等。

对于d=3,您可以执行以下操作(MATLAB伪代码):

v = j'th unit vector
w = v
for i = (1:d)
   v = A*v
   w = w + v
end

向量w现在每个节点都有一个肯定条目,可以在j个步骤中从d节点访问。

答案 3 :(得分:0)

在这种情况下,从给定顶点开始的广度优先搜索是最佳解决方案。你会发现距离d内的所有顶点,你甚至都不会访问任何距离为> = d + 2的顶点。

这是递归代码,尽管通过使用队列可以很容易地完成递归。

// Returns a Set
Set<Node> getNodesWithinDist(Node x, int d)
{
  Set<Node> s = new HashSet<Node>();  // our return value
  if (d == 0) {
    s.add(x);
  } else {
    for (Node y: adjList(x)) {
       s.addAll(getNodesWithinDist(y,d-1);
    }
  }
  return s;
}