题目描述
有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;
}