zoukankan      html  css  js  c++  java
  • HDU 6060 RXD and dividing (最小斯坦纳树)

    RXD and dividing

    题目链接

    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

    题意:
    有n个点,其中1为起点,其余的n-1个点(2~n)为我们要到达的点,将剩余的这n-1个点分成k个集合,看一下到这些点的路径的长度。
    分析: 根据最小斯坦纳树的定义,(就算没有这个定义,我们也应该能够想到这一点,如果要想让路径尽可能的长,那么对于一个节点即它的所有子树来说,最多能够被分成k部分)一条边(u,father(u))对整个的贡献就相当于这条边的value值乘上k,与size [ x ] (当前情况下x的子节点个数,包括它本身)中的较小者,我们只要遍历所有的边,然后将每条边的值都算出来,最后求和。

    
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e6+7;
    int head[N],nxt[N*2],v[N*2],w[N*2],sz[N];
    int n,k,g[N],ed;
    long long ans;
    inline void adg(int x,int y,int z)///头插法
    {
        v[++ed]=y;///v表示的是终点
        w[ed]=z;///w表示的是这条边的权重
        nxt[ed]=head[x];///xt表示的是钱一条边
        head[x]=ed;///头的指向改变
    }
    
    void dfs(int x,int fa,int val)
    {
        sz[x]=1;
        for(int i=head[x]; i!=0; i=nxt[i])
            if(v[i]!=fa)///不是又找到本身这条边了
            {
                dfs(v[i],x,w[i]);
                sz[x]+=sz[v[i]];
            }
        ans+=1ll*min(k,sz[x])*val;
    }
    
    int main()
    {
        while(~scanf("%d%d",&n,&k))
        {
            for(int i=1; i<=n; i++)
                head[i]=0;///每一个点的指向都赋初值
            ed=0;
            ans=0;
            for(int i=1;i<n;i++)
            {
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                adg(x,y,z),adg(y,x,z);
            }
            dfs(1,0,0);
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    中国AI觉醒 阿里王坚:云智能将成为大趋势
    中国AI觉醒 阿里王坚:云智能将成为大趋势
    如何设计scalable 的系统 (转载)
    如何设计scalable 的系统 (转载)
    如何设计scalable 的系统 (转载)
    如何设计scalable 的系统 (转载)
    odoo开发笔记--模型中常用的方法
    odoo开发笔记--模型中常用的方法
    odoo开发笔记--模型中常用的方法
    用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树
  • 原文地址:https://www.cnblogs.com/nanfenggu/p/7900076.html
Copyright © 2011-2022 走看看