1

问题陈述:
给你一个整数N,表示该树中的节点数。现在,您需要计算树中有多少不同的路径,使得该路径中的最小节点值大于或等于k

输入格式:

  1. 第一行包含该树中的节点总数N和一个正整数值K
  2. 下一N-1行包含一对整数u, v(值不是逗号分隔的),表示树中的节点u和之间有一条边。v

例子:

输入:

4 2  
1 2  
2 3  
3 4  

预期输出:

3

编辑:我想不出如何解决这个问题。所以,请给我一个提示,以便我可以进一步尝试实现它。即使是最轻微的帮助,我也将不胜感激。

更新:

1 <= N <= 10^5
1 <= u,v <= N  
1 <= K <= 10^6  

在任何情况下,对此类问题采取天真的方法都不会通过。解决方案的复杂度应该是 O(n**2) 或 O(nlogn)。

4

3 回答 3

2

这个问题可以使用树上的动态编程来解决,你可以在这里阅读它https://www.geeksforgeeks.org/dynamic-programming-trees-set-2/

让我们把问题分成两部分,第一部分是查找节点的子树中有效路径的数量u。第二部分是找到节点的答案,u如果我们不考虑它的子树而是去它的父节点等等。

让我们将 1 视为树的根。

现在为了解决第一部分,我们将创建一个数组in[],我们将在其中存储节点子树中的路径数,u以便in[u]表示从节点开始u并访问其子树的有效路径数。要计算这个数组,我们可以运行一个简单的 dfs,如下所示:

//u is the current node - p is the parent
void dfs1(int u, int p) {
    for (int i = 0; i < g[u].size(); i++) { //iterate through the adjacency of node u
        int v = g[u][i]; // v is the child of u
        if (v != p) { //in case v is the parent just ignore it
            dfs1(v, u); //go to node v
            if (u >= k && v >= k) { //if value of u or v is less than k then we cant start at this node so it should be 0
                in[u] += in[v] + 1; //add to number of paths of u the number of paths starting from the node v + 1 (+1 because we can also go from u to v)
            }
        }
    }
}

为了解决第二部分,我们需要一个数组out[]out[u]其中包含有效路径的数量,如果我们不考虑其子树u将到达其父级u,依此类推。

让我们打电话给u P[u]. 计算out[u]我们将依赖p[u]. out[i]是如果我们去 的有效路径的数量,p[u]一旦我们到达,我们可以做p[u]的是通过它的子树(u当然不包括分支)或访问p[p[u]]( 的父级的父级u),所以out[u](out[p[u]] + 1) + (in[p[u]] - in[u] - 1)

// u is the current node - p is the parent
void dfs2(int u, int p) {
    for (int i = 0; i < g[u].size(); i++) { // iterate through the adjacency of node u
        int v = g[u][i]; // v is the child of u
        if (v != p) { // in case v is the parent just ignore it
            if (v >= k && u >= k) { // if value of u or v is less than k then we cant start at this node so it should be 0
                out[v] += (out[u] + 1); //add to the number of paths of v the number of paths from it's parent (u) + 1 if we dont use the subtree of u
                out[v] += (in[u] - in[v] - 1); // add to the number of paths of v the number of paths from it's parent (u)
                // we should subtract in[v] + 1 because we want to exclude this branch from the subtree of the parent
            }
            dfs2(v, u); // go to node v
        }
    }
}

要找到答案,只需out[u] + in[u]对所有节点求和并除以 2,因为每条路径都计算了两次。

复杂度 O(V+E)

于 2019-02-10T13:18:39.243 回答
1

让我们用一个更简单的情况来解决这个问题,假设树中的所有节点都大于k,所以有效路径的数量是nC2

而且,我们还观察到,有效路径不能包含任何小于 的节点k,因此,我们需要从树中删除所有小于k的节点,这将创建n - k子树,因此最终结果将是

result = sum of nC2 of all subtree

简单算法:

remove all edges that connect to nodes that less than k

for each node that >= k and not marked as visited
  do bfs to count number of node in that subtree
  result += nC2

return result
于 2019-02-10T13:12:54.067 回答
1

对于树,假设我们枚举的路径是从上到下的,我们可以递归地制定它。让f(T, k)表示一个元组 ,[a, b]其中是从开始a的不同有效路径的数量;和,从较低节点开始的不同有效路径的数量。有效路径中的所有节点的值都大于或等于 。TTbTk

然后(Python代码):

def f(T, k):
  if not T["children"]:
    return [0, 0]

  result = [0, 0]

  for c in T["children"]:
    [a, b] = f(c, k)
    result[1] += a + b

    if T["value"] >= k <= c["value"]:
      # One valid path from T to c
      # plus extending all the paths
      # that start at c
      result[0] += 1 + a

  return result

在从树根a + b调用之后,答案将是。f

输出:

T = {
  "value": 1,
  "children": [
    {
      "value": 2,
      "children": [
        {
          "value": 3,
          "children": [
            {
              "value": 4,
              "children": []
            }
          ]
        }
      ]
    }
  ]
}

print f(T, 2)  # [0, 3]
于 2019-02-11T02:25:46.293 回答