Color a tree

Solution

众所周知这是一道dl贪心

Step 1

如果没有先后染色的顺序让你去染色,你肯定会先把最大的节点先染了,但是如果有了限制,类似的,就会把子节点中最大的点先染了,所以两个操作会是连续的。

所以假设待染色的点分别为 x,y,z ,其中 x,y 已知是连续染色,则只有两种染法

1.x+2y+3z1.x+2y+3z 先染 x,y ,再染 z

2.z+2x+3y2.z+2x+3y 先染 z ,再染 x,y

比较两数大小, 1-2=-x-y+2z

也就是比较

(x+y)/2 

也就启发我们运用平均值作为性价比,每次扫描一遍求出最大性价比进行染色,将这一个点放在父亲节点中最后一个点之后马上染色,直到最后将整棵树缩成一个点,得到最终答案

Step 2

复制代码
#include<bits/stdc++.h>
using namespace std;
int n,r,ans;
struct node{int c,fa,t;double w;}num[1005];
int find(){//求出最大性价比
    int mbi;
    double maxn=0;
    for(int i=1;i<=n;i++)
     if(i!=r&&num[i].w>maxn)
      maxn=num[i].w,mbi=i;
    return mbi;
} 
int main(){
    while(scanf("%d %d",&n,&r)&&n&&r){
        ans=0;
        for(int i=1;i<=n;i++)scanf("%d",&num[i].c),ans+=num[i].c,num[i].t=1,num[i].fa=0,num[i].w=num[i].c;//预处理清空
        for(int i=1,a,b;i<n;i++)scanf("%d %d",&a,&b),num[b].fa=a;
        for(int i=1;i<n;i++){
            int tmp=find();
            num[tmp].w=0;
            int f=num[tmp].fa;
            ans+=num[tmp].c*num[f].t;//合并性价比最大的节点,在父亲的节点之后紧跟着被染色
            for(int j=1;j<=n;j++)
             if(num[j].fa==tmp)
              num[j].fa=f;//合并
            num[f].t+=num[tmp].t;//更新父亲节点
            num[f].c+=num[tmp].c;
            num[f].w=(double)(num[f].c)/num[f].t;
        }
        printf("%d\n",ans);//输出
    }
}
复制代码

 

posted @   Coder_cjh  阅读(486)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示