这个问题可以使用树上的动态编程来解决,你可以在这里阅读它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)