为图中的每个节点计算距离 n 处未访问的节点

Posted

技术标签:

【中文标题】为图中的每个节点计算距离 n 处未访问的节点【英文标题】:Counting unvisited nodes at distance n for every node in graph 【发布时间】:2013-03-31 17:24:45 【问题描述】:

对于大图中的每个点,我正在尝试创建一个列表,其中包含距离起始节点 n 处未访问节点的数量。一个示例输出是: [1,3,6] 这意味着在距离 0 处有起始节点本身,在距离 1 处有 3 个新的(未探索的)节点,等等。

如果您只有一个起点,这相当容易:您只需在广度优先搜索的基础上增加一个 shell 计数器。当我必须对图中的每个节点执行此操作时,问题就开始了。因为我的图很大(> 100000 个节点),所以对每个点执行上述例程变得相当慢。

我第一次尝试优化这个是检查节点a 的列表是否可以从a 的所有邻居的列表中构建,但到目前为止我没有运气,部分原因是循环图表。我希望你们中的一些人可能有一些不错的想法,可能涉及一些我可以缓存的额外信息。

我的问题:如果你知道你必须为每个节点做这种搜索,有没有办法优化这种搜索?

【问题讨论】:

all shortest paths problem 基本上是您在按距离和计数分组后所寻求的,而且您可能真的不能比 O(|V|^3) 做得更好。 我的广度优先搜索是 O(|E|),在我的情况下等于 O(|V|)。我必须对每个节点都这样做,所以我目前的复杂度是 O(|V|²)。我现在正在使用并行计算来加快进程,但欢迎提出其他建议! 它应该仍然是 O(|V|*|E|),在最坏的情况下是 O(|V|^3)。但是,如果你说 |V|接近 |E|,那么考虑到有 O(|V|^2) 个可能的顶点组合,您可能需要为其列出最短路径。虽然,如果大多数顶点的度数为 2 或更小,那么简单地列出最长路径(或足够长的路径)并从中提取最短路径可能是可行的。 你为什么称它们为未访问。如果我理解你想知道,给定一个节点,距离 D 有多少个节点,对吧? 您可以获取近似值,还是需要返回精确值? 【参考方案1】:

O(n*|V|^2)以下似乎不太可能有解决方案,所以这里有一个Python中的方法,看起来并不算太糟糕。

# some basic topologies
def lineE(N): 
  return(set((i,i+1) for i in range(N-1)))

def ringE(N):
  return(lineE(N).union([(0,N-1)]))

def fullE(N):
  return(set([(i,j) for i in range(N) for j in range(i)]))

# propagate visitors from x to y
def propagate(V, curr, x, y, d):
  nexty = set()
  for cx in curr[x]:
    if not cx in V[y]["seen"]:
      V[y]["seen"].add(cx)
      V[y]["foaf"][d] = V[y]["foaf"].get(d,0) + 1
      nexty.add(cx)
  return(nexty)

# run for D iterations
def mingle(N, E, D):
  V = dict((i, "seen":set([i]), "foaf":0:1) for i in range(N))
  curr = dict((i, set([i])) for i in range(N))
  for d in range(1, min(D+1, N)):
    next = dict((i, set()) for i in range(N))
    for (h, t) in E:
      next[t] = next[t].union(propagate(V, curr, h, t, d))
      next[h] = next[h].union(propagate(V, curr, t, h, d))
    curr = next
  return(V)

用 10 个节点和距离 3 进行尝试,

N=10
D=3
for (topology, E) in [("line", lineE(N)), ("ring", ringE(N)), ("full", fullE(N))]:
  V = mingle(N, E, D)
  print "\n", topology
  for v in V:
    print v, V[v]["foaf"]

我们得到

line
0 0: 1, 1: 1, 2: 1, 3: 1
1 0: 1, 1: 2, 2: 1, 3: 1
2 0: 1, 1: 2, 2: 2, 3: 1
3 0: 1, 1: 2, 2: 2, 3: 2
4 0: 1, 1: 2, 2: 2, 3: 2
5 0: 1, 1: 2, 2: 2, 3: 2
6 0: 1, 1: 2, 2: 2, 3: 2
7 0: 1, 1: 2, 2: 2, 3: 1
8 0: 1, 1: 2, 2: 1, 3: 1
9 0: 1, 1: 1, 2: 1, 3: 1

ring
0 0: 1, 1: 2, 2: 2, 3: 2
1 0: 1, 1: 2, 2: 2, 3: 2
2 0: 1, 1: 2, 2: 2, 3: 2
3 0: 1, 1: 2, 2: 2, 3: 2
4 0: 1, 1: 2, 2: 2, 3: 2
5 0: 1, 1: 2, 2: 2, 3: 2
6 0: 1, 1: 2, 2: 2, 3: 2
7 0: 1, 1: 2, 2: 2, 3: 2
8 0: 1, 1: 2, 2: 2, 3: 2
9 0: 1, 1: 2, 2: 2, 3: 2

full
0 0: 1, 1: 9
1 0: 1, 1: 9
2 0: 1, 1: 9
3 0: 1, 1: 9
4 0: 1, 1: 9
5 0: 1, 1: 9
6 0: 1, 1: 9
7 0: 1, 1: 9
8 0: 1, 1: 9
9 0: 1, 1: 9

这似乎是正确的。此外,在我的笔记本电脑上运行具有 100000 个节点的距离为 100 的简单拓扑大约需要一分钟。当然,如果你有一个密集的图表(比如fullE),这将会爆炸。

N=100000
D=100
for (topology, E) in [("line", lineE(N)), ("ring", ringE(N))]:
  V = mingle(N, E, D)

【讨论】:

以上是关于为图中的每个节点计算距离 n 处未访问的节点的主要内容,如果未能解决你的问题,请参考以下文章

计算字符串的所有 1-hamming 距离邻居的最快方法?

计算图中节点距离时的关键错误

如何相对于图中的距离创建从单个节点传播的边

如何找到树上一组节点之间的最大距离?

二叉树上节点间的最大距离

如何使用密码计算节点之间的距离/跳跃/长度(#关系)?