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

来源:互联网 发布:苏州网络招募中心 编辑:程序博客网 时间:2024/05/21 17:23

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;}
阅读全文
0 0
原创粉丝点击