C++ 树中所有节点对最短路径之和
树中所有节点对最短路径之和是指计算所有节点对的最短路径的总和。一个有效的方法是使用双重深度优先搜索(DFS)算法。在第一个DFS遍历过程中,确定选择节点与其他节点之间的距离。在第二个DFS遍历过程中,考虑每个节点作为一个潜在的最低公共祖先(LCA),并计算选择的LCA的后代节点对之间的距离。使用这种方法可以计算得到树中所有节点对最短路径的总和,并得到一个理想的解决方案。
使用的方法
- 双重深度优先搜索(DFS)方法
-
动态规划方法
双重深度优先搜索(DFS)方法
对于树中所有节点对最短路径的总和,我们使用双重深度优先搜索(DFS)方法,该方法包括两个DFS遍历过程。首先,我们从任意节点开始计算到所有其他节点的距离。然后,在第二个DFS遍历过程中,我们以每个节点作为潜在的最低公共祖先来遍历树。在遍历过程中,我们计算并累加选择的LCA的后代节点对之间的距离。通过为所有节点重复这个过程,可以得到所有节点对最短路径的总和。这个策略对于解决这个问题非常有效,因为它能够高效地计算树中所有节点对之间的距离总和。
步骤
- 树中的任意节点都可以作为起始节点。
-
从选择的起始节点开始,执行深度优先搜索(DFS)以确定其他所有节点与起始节点的距离。这些距离应该保存在数组或数据结构中。
-
接下来,在树上运行第二次DFS,将每个节点视为可能的最低公共祖先(LCA)。
-
在第二次DFS的过程中,计算选择的LCA的后代节点对之间的距离。对于每个LCA,将这些距离相加。
-
对树中的每个节点重复此过程。
-
所有用最短路径连接的节点对的总和由步骤4中计算得到的所有距离之和表示。
示例
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 10005;
vector<int> graph[MAXN];
int ancestor[MAXN];
int dfs(int node, int lca, int distance) {
int sum = 0;
for (int neighbor : graph[node]) {
if (neighbor != lca) {
sum += dfs(neighbor, lca, distance + 1);
}
}
return sum + distance;
}
int main() {
int lca_node = 0;
int total_sum = 0;
for (int node = 0; node < MAXN; ++node) {
if (node != lca_node) {
total_sum += dfs(node, lca_node, 0);
}
}
cout << "Total sum of distances between descendants of the LCA: " << total_sum << endl;
return 0;
}
输出
Total sum of distances between descendants of the LCA: 0
动态规划方法
我们首先选择任意一个节点作为根节点,并将树转化为基于动态规划的根树,用于计算树中所有节点间最短路径之和。我们利用动态规划计算每个节点与根节点之间的分离距离,并将结果存储在一个数组中。然后对于每个节点,我们将其子节点与根节点的距离求和(已经计算过),以确定所有节点之间的总距离。通过这种方式,我们能够快速计算出所有成对最短路径的总数。作为这个问题的高效解决方案,该算法具有 O(N) 的时间复杂度,其中 N 是树中的节点数量。
步骤
- 将树中的任意节点设为根节点,并将树转化为根树(例如,使用深度优先搜索根节点)。
-
可以使用动态规划确定每个节点距离根节点的距离。这些距离应该存储在一个数组或数据结构中。
-
计算树中每个节点到其他节点的所有距离之和:
a. 遍历当前节点的子节点。
b. 为了考虑通过当前节点的路径,将每个子节点的子树中的节点数和之前计算的每个子节点距离根节点的距离相加。
c. 将这些结果累加到活动节点的每个子节点上。
d. 将当前节点的总和添加到最终结果中。
- 树中所有节点间最短路径之和即为最终结果。
#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
vector<TreeNode*> children;
};
int dfs(TreeNode* node, vector<int>& distances) {
int subtree_size = 1;
for (TreeNode* child : node->children) {
subtree_size += dfs(child, distances);
distances[node->val] += distances[child->val] + subtree_size;
}
return subtree_size;
}
int sumOfAllPairShortestPaths(TreeNode* root) {
vector<int> distances(root->val + 1, 0);
dfs(root, distances);
int total_sum = 0;
for (int distance : distances) {
total_sum += distance;
}
return total_sum;
}
int main() {
TreeNode* root = new TreeNode{0};
int result = sumOfAllPairShortestPaths(root);
cout << "Sum of all pair shortest paths in the tree: " << result << endl;
return 0;
}
输出
Sum of all pair shortest paths in the tree: 0
结论
在树中计算所有节点对之间的最短路径和可以使用双重深度优先搜索(DFS)方法或动态规划。双重DFS方法包括两次遍历,首先计算从选定节点到所有其他节点的距离,然后再次遍历树,将每个节点视为潜在的最低公共祖先(LCA),累加后代节点对之间的距离。动态规划方法通过递归使用DFS将树转换为根,并计算从根到每个其他节点的距离。两种方法的结果是相同的,都是树中所有节点对之间最短路径的和。选择两种算法之间的决策可以基于特定的实现偏好或树结构,但这两种算法都能提供有效的解决方案。
极客笔记