木子亚日乀  

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6060   多校的题目,每次只能写两道SB题,剩下的要么想不到,要么想到了,代码不知道怎么实现,还是写的太少。

题意:N个结点,编号1-N,然后N-1条变将各个点联通相当于一颗生成树,然后将除了1之外的点分成k块,块与块之间不能有重复的点,然后再将1放入各个块中连成一棵生成树,求所有生成树的总和最大是多少?

思路:每一块中都有1号结点,所以我们从一号结点开始遍历其他所有的结点,在此过程中,起初的N-1条边都有各自的贡献度,因为分成k块,所以每天边最多只能贡献k次,所以最终的结果就是:各条边的min(边的贡献度,k)*边的权值的总和。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 1000005
struct Edge{
    int v;
    int w;
    int next;
};
Edge edge[N<<1];
int head[N];
int vis[N];
int cnt;
ll sum;
int n,k;
void add(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int v,int u)
{
    vis[v]=1;
    for(int i=head[v];i!=-1;i=edge[i].next)
    {
        int uu=edge[i].v;
        if(uu==u)
            continue;
        dfs(uu,v);
        vis[v]+=vis[uu];
        ll x=min(k,vis[uu]);
        sum+=x*edge[i].w;
    }
}
int main()
{
    int u,v,w;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        cnt=0;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        sum=0;
        dfs(1,-1);
        printf("%lld\n",sum);
    }
    return 0;
}

 

posted on 2017-09-29 19:06  木子亚日乀  阅读(136)  评论(0)    收藏  举报