算法 - 查找树中直径距离对的数量?

时间:2015-04-17 16:12:11

标签: algorithm tree

我有一个非根的双向未加权非二叉树。我知道如何找到树的直径,树中任何一对点之间的最大距离,但我有兴趣找到具有该最大距离的对的数量。是否有算法可以找到直径距离优于O(V ^ 2)时间的对数,其中V是节点数?

谢谢!

2 个答案:

答案 0 :(得分:2)

是的,有一种线性时间算法可以自下而上运行,类似于只找到直径的算法。这是Java-ish伪代码中的签名;我将算法本身作为练习。

class Node {
    Collection<Node> children;
}

class Result {
    int height;  // height of the tree
    int num_deep_nodes;  // number of nodes whose depth equals the height
    int diameter;  // length of the longest path inside the tree
    int num_long_paths;  // number of pairs of nodes at distance |diameter|
}

Result computeNumberOfLongPaths(Node root);  // recursive

答案 1 :(得分:2)

是的,有一个带O(V + E)时间的算法。它只是找到直径的修改版本。

我们知道我们可以通过两次调用BFS找到直径,首先在任何节点上进行第一次调用,然后记住发现的最后一个节点并运行第二次调用BFS(u),并记住发现的最后一个节点,比如说v。u和v之间的距离给出了直径。

获得具有该最大距离的对数。

1.在调用第一个BFS之前,初始化长度| V |的数组距离和distance [s] = 0.s是任何节点上第一次BFS调用的起始顶点。

2.在BFS中,将while循环修改为:

while(Q is not empty)
 {
  e=deque(Q);
    for all vertices w adjacent to e
     {
       if(w is not visited)
        {
         enque(w)
         mark w as visited
         distance[w]=distance[e]+1
         parent[w]=e
        }
     }
 }

3.就像我说的,记住最后一个访问过的节点,说你是那个节点。现在计算与顶点u处于同一级别的顶点数。 mark是一个长度为n的数组,它的所有值都初始化为0,0意味着顶点最初没有计算。

n1=0
for i = 1 to number of vertices
 {
  if(distance[i]==distance[u]&&mark[i]==0)
   {
    n1++
    mark[i]=1/*vertex counted*/
   }
 }  

n1给出与顶点u处于同一水平的顶点数,现在对于标记为[i] = 1的所有顶点都有标记,并且它们不会再次计数。

4.类似于在u上执行第二个BFS之前,初始化另一个长度为| V |的数组distance2和distance2 [u] = 0。

5.运行BFS(u)并再次获取发现的最后一个节点说v

6.重复第3步,这次是在distance2数组上,取一个不同的变量,说n2 = 0,条件为

if(distance2[i]==distance2[v]&&mark[i]==0)
 n2++
else if(distance2[i]==distance2[v]&&mark[i]==1)
 set_common=1

7.set_common是一个全局变量,当有一组顶点时设置,在任意两个顶点之间,路径是直径,第一个bfs没有标记所有顶点但是至少标记了一个这就是为什么mark [i] == 1。

假设第一个bfs确实在第一次调用中标记了所有这些顶点,那么n2将是= 0并且set_common将不会被设置并且也不需要。但是这种情况与上面相同

在任何情况下,给出直径的对的数量是:=

(n + n2)组合2 - X =(n1 + n2)!/((2!)((n1 + n2-2)!)) - X

我将详细说明X是什么.Else对的数量是= n1 * n2,这是2个不相交的顶点集给出直径的情况

所以使用的条件是

  if(n2==0||set_common==1)
    number_of_pairs=(n1+n2)C2-X
  else n1*n2

现在谈论X.可能会发生标记的顶点可能有共同的父节点。在这种情况下,我们不能计算那些组合。所以在使用上述条件之前,建议运行以下算法

  X=0/*Initialize*/
 for(i = 1 to number of vertices)
  {
   s = 0,p = -1
   if(mark[i]==0)
    continue
   else
   {
    s++
    if(p==-1)
     p=parent[i]
    while((i+1)<=number_of_vertices&& p==parent[i+1])
     {s++;i++}
   }
   if(s>1)
    X=X+sC2
 }

正确性证明

非常简单。由于BFS 逐级遍历树级,n1将为您提供u级别的顶点数量,n2将为您提供v级别的顶点数量因为u和v之间的距离=直径。因此,u级别上的任何顶点与v级别上的任何顶点之间的距离将等于直径。

所用时间为2(| V |)+ 2 * time_of_DFS = O(V + E)。