HDU 6060 minimal Steiner Tree 求贡献值

来源:互联网 发布:国际地图导航软件 编辑:程序博客网 时间:2024/05/18 01:47

minimal Steiner Tree 求贡献值

题意:

给出一个minimal Steiner Tree的树,其实就是一个最小生成树,现在要把2-n的节点分为k部分,每一部部分都是一个点的集合,每隔集合加上节点1都有把所有点链接起来的总cost,求其和,输出最大的和即可。

思路:

我们无法把除了1 的节点的其它节点分成k中情况,因为情况太多。但是边的数量和权值都知道,如果能求出每一条边在分成的集合的出现次数并且把其加起来就是answer。题目中要求最大的哪一种情况,并且要和1节点廉洁在一起,那么把1节点当做根节点,考虑到每一条边其贡献值就是其儿子节点成了k部分的次数,所以取儿子节点的个数和k值得最小值就是一种贪心策略,尽可能的分成不同的部分,然后与此条边的成绩就是贡献。

minimal Steiner Tree在此题的影响并不是很大,因为此图就是一个最小生成树,没有多余的边。

#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <map>using namespace std;const int maxn = 2000005;int n,m;long long sum;vector<int>edge[maxn];map<int,int>mp[maxn];int dfs(int s,int f){    int sonnumber = 1;    int len = edge[s].size();    for(int i = 0;i < len; i++) {        int to = edge[s][i];        if(to != f) {            sonnumber += dfs(to,s);        }    }    if(f != -1)        sum += (long long)mp[f][s]*min(m,sonnumber);    return sonnumber;}int main(int argc, char const *argv[]){    //freopen("in.txt","r",stdin);    while(scanf("%d%d",&n,&m) != EOF) {        for(int i = 1;i <= n-1; i++ ) {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            edge[a].push_back(b);            edge[b].push_back(a);            mp[a][b] = c;            mp[b][a] = c;        }        sum = 0;        dfs(1,-1);        printf("%I64d\n",sum);        for(int i = 1;i <= n; i++) {            edge[i].clear();            mp[i].clear();        }    }    return 0;}
原创粉丝点击