为图中的每个节点计算距离 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 处未访问的节点的主要内容,如果未能解决你的问题,请参考以下文章