HDU 6060 RXD and dividing

来源:互联网 发布:ftp同步软件 linx 编辑:程序博客网 时间:2024/06/06 02:19

题目来戳呀

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,…n into k parts S1,S2,S3,…Sk,
where ⋃Si={2,3,…,n} and for all different i,j , we can conclude that Si⋂Sj=∅.
Then he calulates res=∑ki=1f({1}⋃Si).
He wants to maximize the res.
1≤k≤n≤106
the cost of each edge∈[1,105]
Si 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≤100.

Output

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

Sample Input

5 4
1 2 3
2 3 4
2 4 5
2 5 6

Sample Output

27

Source

2017 Multi-University Training Contest - Team 3

题意:

给你一棵n个节点的树和节点间的 权值,要求将2-n个节点分成k部分,每一部分连接到根节点1(每部分内节点要连接在一起),并且每部分的权值和最大。求出最大权值。
这样形成的权值最大的树是最小斯坦纳树,虽然用不到这个树的定义o(╯□╰)o

难懂的一句话(新增板块XD):

Then he calulates res=∑ki=1f({1}⋃Si). 以为f的自变量是一个数,结果是一堆点…………

想法:

给题目换个解释,将根节点之下的树划分的块数越多,子树之中边经过的次数越多,根节点被经过的次数越多,最后的结果权值越大。

分成2种:
1.除根节点以外的节点子树节点数size[a]≤经过的最大次数k
可以将节点就分成size[a]个部分,这样每一部分都会经过a最多次,一层层的向下遍历即可。
2.size[a]>k
k是被经过的最大次数,即使有再多的子节点还是只能经过k次
不能单独经过的节点可以互相合并但是不能有交集

综上,我们取的是min(k,size[a]),再乘以a到父节点的权值就是其父节点_a的这条边被被利用的最大权值和。依次遍历,累加各边的和就是结果。

tips:

1.size[a]初始化为1,代表不经过其子节点只是由父节点到a。
2.无向图,存两点之间的权值用得是map,因为数组存不下了。
3.注意vector和map的clear,放在最后和最开始是一样的。

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=1e6+10;vector<int>node[maxn];map<ll,ll> dis[maxn];ll sum,a,b,c,n,k;ll cnt[maxn];int bfs(ll a,ll fa,ll cost)///cost为a到父节点fa的权值{    int l=node[a].size();///子节点个数    cnt[a]=1;///起初是其根节点到a的那一次    for(int i=0;i<l;++i)    {        int b=node[a][i];///遍历a子树中的节点        if(b!=fa)            cnt[a]+=bfs(b,a,dis[a][b]);///以a为根节点 b为父节点 遍历b的子树节点 cnt表示在a的子树中 a被经过的次数    }    sum+=cost*min(k,cnt[a]);///预计被经过的最小次数*权值    return cnt[a];}int main(){    while(~scanf("%lld%lld",&n,&k))    {        for(int i=0;i<=n;++i)        {///clear并不真正释放内存 而是类似于初始化         ///真正释放内存可以用swap            node[i].clear();            dis[i].clear();        }        for(int i=0;i<n-1;++i)        {            scanf("%lld%lld%lld",&a,&b,&c);            node[a].push_back(b);            node[b].push_back(a);            dis[a][b]=c;            dis[b][a]=c;        }        sum=0;        bfs(1,-1,0);///最初cost的根节点 设为-1 因为还没有找出来        printf("%lld\n",sum);    }    return 0;}

ps:并没有用到斯坦纳树什么东西+_+看到新鲜事物一下子全都去学最后还没做出来叫嚣着难的人呐qaq