树的分割:DFS后序遍历

该博客探讨了一种图论问题,即如何通过切断通道将n个房间划分为k个金币数大于等于m的连通区域。算法涉及深度优先搜索,通过递归遍历每个节点,检查子树能否形成符合条件的区域。最终,通过解决示例展示了如何判断这种划分是否可行。
摘要由CSDN通过智能技术生成

题目描述

有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;    
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值