查找树上的最小呼叫数

时间:2014-10-04 10:00:50

标签: algorithm tree dynamic-programming

我在接受采访时被问到这个问题,并且在分配的时间里努力正确回答。尽管如此,我认为这是一个有趣的问题,我以前没见过。

假设你有一棵树,根可以打电话(在电话上)每个孩子的孩子,当孩子接到电话时,他可以给每个孩子打电话等等。问题是每次电话都必须在多轮,我们需要尽量减少拨打电话所需的轮数。例如,假设您有以下树:

   A
  / \
 /   \
 B    D
 |
 |
 C

一种解决方案是A在第一轮呼叫D,A在第二轮呼叫B,B在第三轮呼叫C。最佳解决方案是A在第一轮呼叫B,A呼叫D和B在第二轮呼叫C.

请注意,A不能在同一轮中同时调用B和D,任何节点也不能在同一轮中调用多个子节点。但是,具有不同父节点的多个节点可以同时调用。例如,给定树:

      A
    / | \
   /  |  \
   B  C   D
  /\      |
 /  \     |
E   F     G

我们可以有一个序列(其中 - 分隔轮次),例如:

  

A B - B E,A D - B F,A C,D G

(A呼叫B第一轮,B呼叫E,A呼叫D秒,......)

我假设可以使用某种类型的动态编程,但我不确定采用哪种方向。我最初的倾向是使用DFS按顺序排序从根到叶的最长路径,但是当涉及到实际进行调用的节点时,我不确定如何在给定任何树的情况下实现最优性,而不是如何输出最优调用将产生的路径(即在第一个示例中我们可以输出

  

A B - B C,A D

1 个答案:

答案 0 :(得分:2)

我认为这样的事情可以得到最佳解决方案:

  1. 假设'调用'对于每个叶子是1
  2. 为每个节点获取所有孩子的呼叫值,并根据他们的呼叫对其进行排名'值
  3. 将每个孩子的等级视为'排名'
  4. 计算'来电的价值'为每个节点循环他的孩子(计算他们的排名后)并找到'电话的最大价值' +'排名'
  5. '电话'根节点的值是答案
  6. 它在树上进行动态编程,你可以像这样递归地实现它:

    int f(node v)
    {
       int s = 0;
       for each u in v.children
       {
          d[u] = f(u)
       }
       sort d and rank its values in r (r for the maximum u would be 1)
       for each u in v.children
       {
          s = max(s, d[u] + r[u] + 1)
       }
       return s
    }
    

    祝你好运!