可以被K整除连通块的最大数目

给你一棵 n 个节点的无向树,节点编号为 0 到 n - 1 。给你整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 有一条边
同时给你一个下标从 0 开始长度为 n 的整数数组 values ,其中 values[i] 是第 i 个节点的 值 。再给你一个整数 k
你可以从树中删除一些边,也可以一条边也不删,得到若干连通块。一个连通块的值定义为连通块中所有节点值之和。如果所有连通块的值都可以被 k 整除,那么我们说这是一个合法分割
请你返回所有合法分割中,连通块数目的最大值

一. 贪心分割

class Solution {
public:
    int maxKDivisibleComponents(int n, vector<vector<int>>& edges, vector<int>& values, int k) {
        //贪心进行分割,如果子树满足条件,子树中某个叶子节点也满足条件,那这颗子树必然可以进行再划分
        //所以可以选择贪心从叶子节点进行分割
        unordered_set<int> s[n];

        for(auto &edge:edges){
            s[edge[0]].insert(edge[1]);
            s[edge[1]].insert(edge[0]);
        }
        queue<int> q;
        for(int i=0;i<n;i++)
            if(s[i].size()==1||s[i].size()==0) q.push(i);
        int cnt = 0;
        while(!q.empty()){
            int cur = q.front(); q.pop();
            if(values[cur]%k==0) cnt++;
            for(auto next:s[cur]){//遍历领接边
                s[next].erase(cur);//删除关系
                if(s[next].size()==1)    q.push(next);
                if(values[cur]%k!=0) values[next]+=values[cur];
            }
        }
        return cnt;
    }
};

二. 树形dp

class Solution {
public:
    int maxKDivisibleComponents(int n, vector<vector<int>>& edges, vector<int>& values, int k) {
        vector<vector<int>> g(n);
        for (auto &e : edges) {
            int x = e[0], y = e[1];
            g[x].push_back(y);
            g[y].push_back(x);
        }

        int ans = 0;
        function<long long(int, int)> dfs = [&](int x, int fa) -> long long {
            long long sum = values[x];
            for (int y : g[x])
                if (y != fa)
                    sum += dfs(y, x);
            ans += sum % k == 0;
            return sum;
        };
        dfs(0, -1);
        return ans;
    }
};
posted @ 2023-10-01 14:20  失控D大白兔  阅读(9)  评论(0编辑  收藏  举报