leetcode [834. 树中距离之和]

(https://leetcode-cn.com/problems/sum-of-distances-in-tree/)

这题可以按照官方题解的树形dp再加上换根法来做(不要被这个名字给吓到,仔细想想其实也不是很难),也可以来找规律来做。下面记录一下我的思路

因为题目给的是无向树,所以以谁为根节点都无所谓,那首先想到的就是可以对每个结点进行一次dfs,答案也就出来了,但这个复杂度有点高;

其实在纸上画画之后我们发现可以将根节点的答案转移到他的子节点。假设u是v的父节点,以u为根节点和以v为根节点答案有什么不同?当以v为根节点时,v自己和v的孩子的距离会减一(与u做根节点相比),而除此之外的其他所有点的距离会加一;那这就简单了,我们只需要只要父节点的答案和当前结点的孩子的个数,我们就可以推出当前结点的答案:val_now = val_fa + (N-2*nums)。val_now是当前结点的答案,val_fa是父节点的答案,nums是当前结点的孩子个数+1(加的是自己本身)。至于nums和最开始的根节点的答案用一个dfs就能求出来了

/*
对于一个点v来说,我需要知道他的孩子的个数
如果我知道v的父节点的情况,那么:从父节点的状态就可以转移到当前结点
 val_now = val_fa + (N-2*nums)
*/
const int maxn = 1e4+50;
class Solution {
public:
    vector<int> edge[maxn];
    vector<int> ans;
    int nums[maxn],val0,N;
    void dfs(int now,int fa,int step){
        nums[now] = 1;
        val0 += step;
        for (auto &c : edge[now]){
            if (c == fa) continue;
            dfs(c,now,step+1);
            nums[now] += nums[c];
        }
    }
    void ChangeRoot(int now,int fa){
        for (auto &c : edge[now]){
            if (c == fa) continue;
            ans[c] = ans[now] + (N - 2*nums[c]);
            ChangeRoot(c,now);
        }
    }
    vector<int> sumOfDistancesInTree(int N, vector<vector<int>>& edges) {
        for (int i = 0; i < maxn; i++) edge[i].clear();
        this->N = N;
        ans.resize(N);
        for (auto &v : edges){
            edge[v[0]].push_back(v[1]);
            edge[v[1]].push_back(v[0]);
        }
        val0 = 0;
        dfs(0,-1,0);
        ans[0] = val0;
        ChangeRoot(0,-1);

        return ans;
    }
};
"没有天赋异禀,那就加倍努力"
原文地址:https://www.cnblogs.com/Beic233/p/13774050.html