题目链接: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; }

浙公网安备 33010602011771号