/** 题目:hdu6060 RXD and dividing 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6060 题意:贪心 给定一颗树,n个节点,编号为1~n。将2~n编号的节点分成k份。 每一份分别和编号1的节点取并集。然后求每一份的节点连通的最小边权和; 然后k份获得的边权和加起来;问:求可以获得的k份边权和的总和的最大值。 思路:通过画树容易发现,假如k无穷大,如果节点x为根的子树有num个节点,那么x与x的父节点相连的那条边权最多加num次。 所以每个节点x与父节点相连的边的权值w的贡献为min(num,k)*w; num为以x为根的子树的总结点数。 */ #include<iostream> #include<cstdio> #include<algorithm> #include<map> #include<vector> #include<queue> #include<set> #include<cstring> #include<time.h> #include<random> #include<cmath> using namespace std; typedef pair<int,int> P; typedef long long LL; const int mod = 1e9+7; const int INF = 0x3f3f3f3f; const int maxn = 1e6+100; int n, k; vector<P> G[maxn]; struct node { int sum; int w; }t[maxn]; void dfs(int r,int f) { int len = G[r].size(); t[r].sum = 1; for(int i = 0; i< len; i++){ if(G[r][i].first==f) continue; dfs(G[r][i].first,r); t[G[r][i].first].w = G[r][i].second; t[r].sum += t[G[r][i].first].sum; } } int main() { while(scanf("%d%d",&n,&k)==2) { for(int i = 1; i <= n; i++) G[i].clear(); int u, v, w; for(int i = 1; i < n; i++){ scanf("%d%d%d",&u,&v,&w); G[u].push_back(P(v,w)); G[v].push_back(P(u,w)); } dfs(1,-1); LL ans = 0; for(int i = 2; i <= n; i++){ ans = (ans+(LL)min(t[i].sum,k)*t[i].w); } printf("%lld\n",ans); } return 0; }
时间: 2024-10-26 07:25:46