hdu 多校联赛 RXD and dividing

来源:互联网 发布:量表数据怎么录入excel 编辑:程序博客网 时间:2024/06/04 19:11

RXD and dividing

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1655    Accepted Submission(s): 710


Problem Description
RXD has a tree T, with the size of n. Each edge has a cost.
Define f(S) as the the cost of the minimal Steiner Tree of the set S on tree T
he wants to divide {2, 3, 4, 5, 6, \dots n} into k parts S_1, S_2, S_3, \dots S_k,
where \bigcup S_i = \{2, 3, \dots , n \} and for all different i, j , we can conclude that S_i \bigcap S_j = \emptyset
Then he calulates res = \sum_{i = 1}^{k}{f(\{1\}\bigcup S_i)}.
He wants to maximize the res.
1\leq k\leq n\leq 10^6
\text{the cost of each edge} \in [1, 10^5]
S_i might be empty.
f(S) means that you need to choose a couple of edges on the tree to make all the points in S connected, and you need to minimize the sum of the cost of these edges.f(S) is equal to the minimal cost 
 

Input
There are several test cases, please keep reading until EOF.
For each test case, the first line consists of 2 integer n, k, which means the number of the tree nodes , and k means the number of parts.
The next n - 1 lines consists of 2 integers, a, b, c, means a tree edge (a, b) with cost c.
It is guaranteed that the edges would form a tree.
There are 4 big test cases and 50 small test cases.
small test case means n \leq 100.
 

Output
For each test case, output an integer, which means the answer.
 

Sample Input
5 41 2 32 3 42 4 52 5 6
 

Sample Output
27
 

Source
2017 Multi-University Training Contest - Team 3
 

Recommend
liuyiding


题意:

 补这道题题的时候就马马虎虎 样例都解释不了 理解的也还不够透彻 后来问同学才知道这道题就是给出一个n个节点的树, 将从2到n的部分分成k部分, 然后再将1号节点加到每一个部分上, 然后每一部分的值定义为其中的点在树上的最小的斯坦纳树, 然后求这些值得和的最大值是多少 
思路;

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

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

ac代码:理解的还不够透彻 有错误希望大家能够指出

#include <bits/stdc++.h>using namespace std;const int N = 1e6+7;typedef  long long LL;const LL mod = 1e9+7;struct node //建立一个结构体{    int v;//v用来存储点    LL w;//w用来存储距离};vector<node>p[N];//建立node类型的容器 提高运算速度LL ans;int d[N];//用来记录N这个点作用的快的数量int n, k;void dfs(int u,int f,LL dist)//深搜的函数{    d[u]=1;    for(int i=0;i<p[u].size();i++)//遍历图中所有的点    {        int v=p[u][i].v;        if(v==f)            continue;//如果树遍历到头 就跳出此次循环         dfs(v,u,p[u][i].w);//到已遍历节点的子节点去        d[u]+=d[v];    }    ans+=dist*(LL)min(k,d[u]);//这个点的长度*他作用的块的数量 注意块的数量不能超过k}int main(){    while(scanf("%d %d", &n, &k)!=EOF)    {        for(int i=0;i<=n;i++)            p[i].clear();//初始化容器        for(int i=0;i<n-1;i++)//输入两点和两点间的路径长度        {            int x, y;            LL z;            scanf("%d %d %d", &x, &y, &z);            p[x].push_back((node){y,z}),p[y].push_back((node){x,z});//将两点间的关系添加到vector中        }        ans=0;//初始化合值        memset(d,0,sizeof(d));        dfs(1,0,0);//从第一个点开始深搜        cout<<ans<<endl;    }    return 0;}


原创粉丝点击