树的分割:DFS后序遍历

题目描述

有n个房间,房间之间有通道相连,一共有n-1个通道,每两个房间之间都可以通过通道互相到达。

通过封闭一些通道来把n个房间划分成k个互相不连通的区域,他希望这k个区域内部的金币数目和都大于等于m,是否可行。

示例1
输入
3,2,3,[1,2],[2,3],[3,1,2]
返回值
true

说明
切断1和2之间的通道,划分出了2个金币数为3的连通块

第一个参数n代表房间数量
第二个参数k代表要划分成k块区域。
第三个参数m代表每块区域的金币数要大于等于m
第四、五个参数vector u,v代表通道,通过通道相连
第六个参数vector x代表每个房间的金币数

求解思路

容易知道这是一颗生成树,那么从任意节点出发(1号节点)
若采取后续遍历的方式,
若某棵树值>=m 那么减去这一部分返回0 找到一个符合要求的分区
否则返回这颗子树的值

采取map<int,vector> 记录每个节点的子节点信息
采取 int dfs(int p,int&k,int m,vector& x) 返回p节点所在子树的值

代码实现

    map<int,vector<int>> mp;

    int dfs(int ptr,int& k,int m,vector<int>&x)
    {
        if(k<=0)   //只要能划分出k组 大于等于m的分组 就可以结束寻找
            return 0;  
        int sum=x[ptr];//当前研究的点
        for(auto item:mp[ptr])
            sum+=dfs(item,k,m,x);  //从子节点中返回
        if(sum>=m)  //如果以ptr开始的树  所在子树和大于等于m 那么减去这部分
        {
            k--;//一组符合要求的分组
            return 0;  //注意这里返回0  因为减去了
        }
        return sum;//否则返回这个分组
    }
    
    bool solve(int n, int k, int m, vector<int>& u, vector<int>& v, vector<int>& x) {
        // write code here
        for(int i=0;i<n-1;i++)
        {
            mp[u[i]].push_back(v[i]);  //相互连接的边  注意这里map中只存单向的  避免循环引用
        }
        dfs(1,k,m,x);
        return k<=0;    
    }
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页