• poj2054 Color a Tree 题解报告


    题目传送门

    【题目大意】

     一棵有$n$个节点的树,每个节点$i$都有一个权值$A_i$。现在要把这棵树的节点全部染色,规则为:根节点$R$可以随时被染色;对于其他节点,在被染色之前它的父亲节点必须已经染上了色。每次染色的代价为$T*A_i$,其中$T$代表当前是第几次染色。求把这棵树染色的最小总代价。

    【思路分析】

    这题容易有一个错误的算法就是“每一步在可以被染色的点里选权值最大的染色”,我们明显可以构造出反例——一个权值很小的节点下面有很多权值巨大的节点,另一个权值较大的节点却没有子节点。不过我们可以从中提取出一个正确的性质:树中除根节点外权值最大的点,一定会在它的父节点被染色后立即染色。于是我们可以确定的是,树中权值最大的点及其父节点的染色操作是连续进行的,我们可以把这两个点“合并起来”。合并得到的新点的权值设为这两个点的权值的平均值。

    于是贪心策略就是每次选择权值最大的点与其父亲节点合并,直到最后把整棵树合并成一个点,再按照顺序计算答案。

    【代码实现】

     1 #include<cstdio>
     2 #include<iostream>
     3 #define rg register
     4 #define go(i,a,b) for(rg int i=a;i<=b;i++)
     5 #define ll long long
     6 using namespace std;
     7 const int N=1002;
     8 int n,root,fa[N],a[N],num[N];
     9 ll ans=0;
    10 int main(){
    11     scanf("%d%d",&n,&root);
    12     while(n&&root){
    13         go(i,1,n) scanf("%d",&a[i]),num[i]=1;
    14         //num记录这个点所含原节点的数量
    15         go(i,1,n-1){
    16             int x,y;
    17             scanf("%d%d",&x,&y);
    18             fa[y]=x;
    19         }
    20         go(i,1,n-1){
    21             double maxn=0;int now;//now记录要合并的节点
    22             go(i,1,n)
    23                 if(i!=root&&1.0*a[i]/num[i]>=maxn)maxn=1.0*a[i]/num[i],now=i;
    24             go(i,1,n)
    25                 if(fa[i]==now) fa[i]=fa[now];
    26             ans+=a[now]*num[fa[now]];//合并
    27             num[fa[now]]+=num[now];
    28             a[fa[now]]+=a[now];a[now]=0;
    29         }
    30         ans+=a[root];
    31         printf("%lld
    ",ans);
    32         scanf("%d%d",&n,&root);ans=0;
    33     }
    34     return 0;
    35 }
    代码戳这里
  • 相关阅读:
    cin、cout、cerr、clog------c++ Primer Plus
    c++ 用new后delete,而继续输出指针后果 new/new[]/delete/delete[]区别
    c++类
    c++内联 inline
    c++ 委托构造函数
    c++ explicit
    activti表结构
    工作流设计
    问题解决
    grep 命令
  • 原文地址:https://www.cnblogs.com/THWZF/p/11257688.html
Copyright © 2020-2023  润新知