hdu 6060 RXD and dividing 2017多校第三场第五题(思维+dfs)

本文解析了HDU6060 RXDanddividing题目,介绍了一棵树上如何将节点分为k部分使得从根节点到各部分的权值之和最大。通过理解最小斯坦纳树概念,提出了针对该问题的有效解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hdu 6060 RXD and dividing
题目大意,一棵树有n个节点,1为根节点,将2~n这n各节点分为k部分。这k个部分没有交集,可以为空,求1到k部分的和最大。
解题思路:这里提到了最小斯坦纳树,对此一无所知不知道要怎么弄,后来发现这里有n个节点n-1条边这样形成的树本来就是一棵最小生成树了,然后最小生成树又是斯坦纳树的一种特殊情况,所以这里可以忽略斯坦纳树的情况。而我们需要考虑的是某些边的重用情况。
记边 (u, v) 的权重为 w[v],以点 v 为根的子树的节点总数为 sz[v],那么答案就是 w[v] * min(sz[v], k) 对每个点求个和。这里我们要明白一点那就是,如果想让一条边尽量多用,那么它的子节点就应该尽可能分成多部分,这里他分成最多的部分是min(sz[i],k)最多是k部分,因为题目要求把n-1个节点分成k部分,所以w【v】最大的贡献是k,开始我一直觉得,这样算不能囊括所有的节点,后来才发现,原来这里分成的k部分是以叶子节点来分的,若k=1 就直接是原来那棵树的权重,若k>=2,先将叶子结点分成一部分,然后可以视为叶子结点已经不存在,再将新的叶子节点看成一部分,剩余的看做一部分,这样就可以保证囊括所有节点了。
code:

#include <bits/stdc++.h>
using namespace std;
struct Node
{
    int v,w;
};
vector<Node> e[1000010];
int sz[1000010],w[1000010];
void dfs(int v,int pre)
{
    sz[v] = 1;
    for(int i=0;i<e[v].size();i++)
    {
        int u = e[v][i].v;
        if(u == pre)
            continue;
        w[u] = e[v][i].w;
        dfs(u,v);
        sz[v] += sz[u];
    }
}
int main()
{
    int n,k;
    while(~scanf("%d %d",&n,&k))
    {
        for(int i=0;i<=n;i++)
            e[i].clear();
        int a,b,c;Node temp;
        for(int i=1;i<n;i++){
            scanf("%d %d %d",&a,&b,&c);
            temp.v = b; temp.w = c;
            e[a].push_back(temp);
            temp.v = a; temp.w = c;
            e[b].push_back(temp);
        }
        memset(sz,0,sizeof(sz));
        memset(w,0,sizeof(w));
        dfs(1,0);
        long long ans = 0;
        for(int i = 2;i<=n;i++)
            ans += w[i]*(long long)min(sz[i],k);
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值