如何从给定的节点集中等距离地查找图中的所有节点?

时间:2013-03-26 21:28:47

标签: algorithm graph complexity-theory graph-algorithm

如果您有一个简单的无向图G(V,E)F,它是V的子集。如何找到某个节点v,使Fv中每个节点的距离相同,距离最小化?如果没有None,请返回v。我被告知这可以在O(|V|+|E|)复杂性中完成。

假设所有边都距离为1。

任何人都可以解释如何做到这一点?伪代码也会有所帮助。

2 个答案:

答案 0 :(得分:3)

解决方案类似于BFS,但稍作修改:

  1. 从S = F开始,标记F节点。

  2. 查找| S |从S中的每个元素设置距离1(所有这些集合应包含未标记的节点)。如果这些集合的交集非空,则找到候选者。

  3. 取| S |的并集在S'中设置上面并标记这些节点。如果S'为空,则返回“无”。

  4. 返回第2步。

  5. 假设所有设置操作都需要恒定时间,那么算法的复杂度与BFS相同,即O(| V | + | E |)。

    现在推断集合操作的复杂性。我的理由是,设置操作不会增加复杂性,因为步骤2和3中的并集和交叉操作可以组合起来花费时间O(| S |),并且因为在每个步骤S与之前迭代中的S不同,集合操作的总体复杂度为O(| V |)。

答案 1 :(得分:2)

这是一种伪代码算法,试图添加注释来解释它是如何工作的。

declare explored // a table of all the vertices that can keep track of one number (distance, initialized to -1) and a list of vertex references (origins, initialized to null)
to_explore = S  // fifo queue of vertices to explore

while (to_explore not empty) {
    pop vertex v from to_explore
    current_distance = explored[v].distance
    current_origins = explored[v].origins
    for (vertex n, neighbor of v) {
        if (explored[n].origins contains v)
            continue // we just hit a loop and we're only interested in shortest distances
        if (explored[n].distance == -1) { // first time we come here
            explored[n].distance = current_distance+1
            explored[n].origins = current_origins
            push n to to_explore
            continue
        }
        if (explored[n].distance != current_distance+1) {
            continue // we are merging path from another node of S but different distance, cannot lead to any solution
        }
        // only case left is explored[n].distance == current_distance+1
        // so we've already come here from other place(s) in S with the same distance
        add / merge (without duplicates) origins to explored[n].origins
        if (explored[n].origins = S) // maybe compare the size is enough?
            return n // we found a solution
        // if not , we just continue our exploration, no need to add to the queue since we've already been through here before
    }
}

我们的想法是,通过FIFO队列,我们​​将探索距离集合S的距离为1的所有内容,如果我们在那里找不到任何解决方案,距离2处的所有内容......等等。所以我们会找到最短的距离第一。

我并不完全确定复杂性,但我相信在最坏的情况下,我们只会探索每个顶点和每个边缘一次,这样才能得到O(|E| + |V|)。但在某些情况下,我们多次访问相同的顶点。虽然这不会增加探索的路径,但我不确定是否应该有一个因素| S |在某个地方(但如果这只是一个常数,那就没问题了......)

希望我没有错过任何东西。显然我没有测试任何这个.... :)

编辑(回复评论)

  

您的代码是否适合这样的图表? E =(a,b),(a,c),(a,d)   ,(b,e),(c,e),(d,e),我的F = {b,c,d}。说,你开始吧   bfs用。我怀疑,最终genins数组只有{a}   因此代码将返回None。 - Guru Devanla

在这种情况下,会发生以下情况:

to_explore is initialized to {b,c,d}
//while (to_explore not empty)
pop one from to_explore (b). to_explore becomes {c,d}
current_distance=0
current_origins={b}
//for (neighbors of b) {
handling 'a' as neighbor of b first
explored[a].distance=1
explored[a].origins={b}
to_explore becomes {c,d,a}
//for (neighbors of b)
handling 'e' as next neighbor of b
explored[e].distance=1
explored[e].origins={b}
to_explore becomes {c,d,a,e}
//while (to_explore not empty)
pop one from to_explore (c). to_explore becomes {d,a,e}
current_distance=0
current_origins={c}
//for (neighbors of c)
handling 'a' as neighbor of c first
explored[a].distance is already 1
explored[a].origins={b,c}
to_explore already contains a
//for (neighbors of c) {
handling 'e' as next neighbor of b
explored[e].distance is already 1
explored[e].origins={b,}
to_explore already contains e
//while (to_explore not empty)
pop one from to_explore (d)
current_distance=0
current_origins={d}
//for (neighbors of d)
handling 'a' as neighbor of d first
explored[a].distance is already 1
explored[a].origins={b,c,d}
that matches F, found a as a solution.