关闭

hdu 6060 RXD and dividing

标签: 2017多校
323人阅读 评论(0) 收藏 举报
分类:

链接

题意:

有一颗n个节点的树,现在将节点2-n分成k组,定义每组的的权值为该组内所有点加编号为1的节点相互连接所经过的边的权值的和,求k组点集最大的和。

分析:

使用贪心的思想,我们思考每条边对最终答案的贡献。既然要结果最大,那么每条边就尽可能的多被走到。
这里写图片描述

如上图,现在考虑A-C这条边所做的贡献,很容易想到,在计算一个分组的权值时,如果C点或C的子节点有一个是属于该分组的 , 那么在计算该分组的权值的A-C这条边就会被走过。那么我们如何保证使得A-C边尽量多的走过呢?其实只要C和C的子节点所属的组尽量的多就好了。设节点C和C的子节点数为m。

分两种情况:

1.m大于等于k , 那么我们认定A-C会经过k次。
2.m小于k , 那么我们认定A-C会经过m次。

ac代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7+1000;
struct
{
    int to , value , next;
}edge[maxn];
int head[maxn] , cnt , k; long long ans;
void add_edge(int from , int to , int value)
{
    edge[++cnt].to = to;
    edge[cnt].value = value;
    edge[cnt].next = head[from];
    head[from] = cnt;
}
int dfs(int fa , int x , int value)
{
    int sum = 1;
    for(int i=head[x]; i; i=edge[i].next)
    {
        int to = edge[i].to;
        if(fa != to)
            sum += dfs(x , to , edge[i].value);
    }
    if(sum > k)
        ans += (long long)k*value;
    else
        ans += (long long)sum*value;
    return sum;
}
int main(int argc , char argv[])
{
    int n , a , b , value;
    while(~scanf("%d %d", &n , &k))
    {
        cnt = 0;
        memset(head , 0 , sizeof(head));
        for(int i=1; i<n; i++)
        {
            scanf("%d %d %d", &a , &b , &value);
            add_edge(a , b , value);
            add_edge(b , a , value);
        }
        ans = 0;
        dfs(0 , 1 , 0);
        printf("%lld\n", ans);
    }
    return 0;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:14755次
    • 积分:924
    • 等级:
    • 排名:千里之外
    • 原创:79篇
    • 转载:0篇
    • 译文:0篇
    • 评论:7条
    最新评论