834 树中距离之和

这道题我自己的想法只有对每个点都用一遍Dijkstra然后再求和,显然会超时,所以我都没有尝试。

研究了一下题解,发现题解很巧妙,自己对树的处理还是太稚嫩,之前树链剖分学的都忘光了。

对于固定根节点的,我们应该使用树状dp:
d p [ u ] = ∑ v ∈ s o n ( u ) d p [ v ] + s z [ v ] dp[u]=\sum_{v\in son(u)} dp[v]+sz[v] dp[u]=vson(u)dp[v]+sz[v]
其中, d p [ u ] dp[u] dp[u]表示以u为根节点的子树中根节点u到其儿子节点的所有距离之和,之所以加上 s z [ v ] sz[v] sz[v]是因为长度为1,如果长度不固定的话只需要乘上长度就可以了。

通过上面的dp我们可以算出以一个节点为根节点的答案,但是其他节点呢?朴素的想法是对其他节点每个也进行相同的操作,这样的时间复杂度是 O ( n 2 ) O(n^2) O(n2),好像还可以接受。

题解给出了更优秀的做法:假设我们已经求出了以节点u为根节点的树的答案 d p [ u ] dp[u] dp[u],对于其直接孩子v,我们是有办法直接求出以v为根节点的答案的。

最主要的性质是:如果更换了根节点,只会影响这两个相邻节点的dp值,对其他节点的dp值是不会有影响的。因此我们只需要更新这两个节点即可。

首先我们应该从 d p [ u ] dp[u] dp[u]中减去 d p [ v ] + s z [ v ] dp[v]+sz[v] dp[v]+sz[v],因为这个时候是以v为根节点的,然后更新 s z [ u ] sz[u] sz[u],然后再给 d p [ v ] dp[v] dp[v]加上 d p [ u ] + s z [ u ] dp[u]+sz[u] dp[u]+sz[u],再更新 s z [ v ] sz[v] sz[v]。这样就得到了正确的答案。

代码实现的话首先进行一次树状dp,然后再进行回溯。

发现题解中的代码很精炼,仔细学习了一下自己实现了一个差不多的,几乎没有区别。学到了使用 e m p l a c e _ b a c k emplace\_back emplace_back的复杂度好像更加优秀。

还是要多做hard题目,对自己的提升比较大。

class Solution {
public:
    vector<int> dp,sz,ans;
    vector< vector<int> > graph;
    void Init(int n, vector<vector<int> >&edges)
    {
        dp.resize(n, 0);
        sz.resize(n, 0);
        ans.resize(n, 0);
        graph.resize(n, {});
        int u,v;
        for(auto& edge:edges)
        {
           u = edge[0]; v = edge[1];
           graph[u].emplace_back(v);
           graph[v].emplace_back(u);
        }
    }
    void dfs(int u,int father)
    {
        sz[u] = 1; dp[u] = 0;
        for(auto& v:graph[u])
        {
            if(v == father) continue;
            dfs(v, u);
            sz[u] += sz[v];
            dp[u] += dp[v] + sz[v];
        }
    }
    void dfs2(int u, int father)
    {
        ans[u] = dp[u];
        int dpu, dpv, szu, szv;
        for(auto& v:graph[u])
        {
            if(v == father) continue;
            dpu = dp[u]; dpv = dp[v];
            szu = sz[u]; szv = sz[v];

            dp[u] -= dp[v] + sz[v];
            sz[u] -= sz[v];
            dp[v] += dp[u] + sz[u];
            sz[v] += sz[u];
            dfs2(v, u);

            dp[u] = dpu; dp[v] = dpv;
            sz[u] = szu; sz[v] = szv;
        }
    }
    vector<int> sumOfDistancesInTree(int N, vector<vector<int>>& edges) {
        Init(N, edges);
        dfs(0, -1);
        dfs2(0, -1);
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要计算中两个节点之间的距离,可以使用深度优先搜索(DFS)或广度优先搜索(BFS)算法。以DFS为例,我们可以从根节点开始,依次遍历每个节点,并记录每个节点的深度(即距离根节点的距离)。当我们遍历到目标节点时,就可以根据记录的深度计算出两个节点之间的距离。 下面是一个示例代码,用于计算中两个节点之间的距离: ```python # 定义一个函数,用于计算中两个节点之间的距离 def get_distance(root, node1, node2): # 记录每个节点的深度 depths = {} # 记录每个节点的父节点 parents = {} # 从根节点开始进行深度优先搜索 def dfs(node, depth, parent): depths[node] = depth parents[node] = parent # 如果找到了目标节点,就返回 if node == node1 or node == node2: return # 否则继续遍历子节点 for child in node.children: dfs(child, depth + 1, node) dfs(root, 0, None) # 计算两个节点的距离 distance = 0 while node1 != node2: if depths[node1] < depths[node2]: node1, node2 = node2, node1 node1 = parents[node1] distance += 1 return distance ``` 在这个函数中,我们首先遍历,记录每个节点的深度和父节点,然后通过一个while循环,计算两个节点之间的距离。在循环中,我们通过比较两个节点的深度,不断向上移动深度更深的节点,直到两个节点的深度相等为止。在每次移动节点时,我们都会将距离加1。最后,函数返回的就是两个节点之间的距离。 需要注意的是,这个函数假设中不存在环,即任意两个节点之间只有一条路径。如果存在环,那么计算两个节点之间的距离就比较复杂,可能需要使用更复杂的算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值