HDU 1055

一棵树,结点树为n,根结点为r。每个结点都有一个权值ci,开始时间为0,每染色一个结点需要耗时1,
每个结点的染色代价为ci*ti(ti为当前的时间),
每个结点只有在父结点已经被染色的条件下才能被染色。
求染完整棵树需要花费的最小代价。

找出当前最大子节点和其父节点合并成新的节点
直到点集中只剩一个节点
因为合并时将子节点的权值加在父节点上
则 每次更新 答案加上当前子节点的权值乘上父节点的花费时间,这个很神奇
因为合并后,当对其父节点操作时也会重复加上子节点权值,
即累加起来等同于每一个节点的最初权值乘上对应时间

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct node{
    int f,v,t;
    double w;//权值
}p[1005];
int n,r,a,b;
int main()
{
    while(~scanf("%d%d",&n,&r),n+r)
    {
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&p[i].v);
            p[i].w=p[i].v;
            p[i].t=1;
            ans+=p[i].v;
        } 
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            p[b].f=a;
        }
        double wmax;
        int pos,fa;
        for(int i=1;i<n;i++)
        {
            wmax=-1;
            for(int j=1;j<=n;j++)//找当前大子节点 
            {
                if(j==r) continue;//子节点!
                if(wmax<p[j].w)//点权值比较时对比算数平均值 
                {
                    wmax=p[j].w;
                    pos=j;
                }
            }
            p[pos].w=-1;//去掉子节点
            fa=p[pos].f;
            ans+=p[pos].v*p[fa].t;//更新答案 
            for(int j=1;j<=n;j++)//将子节点的子节点全部接在新建节点上 
                if(p[j].f==pos) p[j].f=fa;
            p[fa].v+=p[pos].v;//新节点在父节点位置,节点的总权值等同于父子权值和 
            p[fa].t+=p[pos].t;//个数 
            p[fa].w=1.0*p[fa].v/p[fa].t;//比较时权值等于算术平均值
        }
        printf("%d
",ans);
    }
}
我自倾杯,君且随意
原文地址:https://www.cnblogs.com/nicetomeetu/p/5465941.html