Pku2054 Color a Tree

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目:传送门

翻译如下

          问题A:Pku2054给树上色

描述

现在要对这N个结点依次进行
染色,每个结点染色要花费1个单位的时候,同时要满足一个结点仅在其
父亲被染色后才可被染色,每个结点有个权值Ci,如果我们在第Ti时间对
i号结点染色,则付出总代价为Sigma(Ti * Ci),1 <= i <= N。
现在认为这个树和每个点的权值,请构造一种染色顺序,使总代价最小。

输入项

输入包含几个测试用例。每种情况的第一行均包含两个整数N和R(1 <= N <= 1000,1 <= R <= N),其中N是树中的节点数,R是根节点的节点数。第二行包含N个整数,其中第i个为Ci(1 <= Ci <= 500),即节点i的着色成本因子。接下来的N-1行中的每一行都包含两个以空格分隔的节点号V1和V2,它们是树中边缘的端点,表示V1是V2的父节点。没有边缘将被列出两次,并且所有边缘将被列出。N = 0和R = 0的测试用例表示输入结束,不应进行处理。

输出量

对于每个测试用例,输出一行,其中包含Bob着色所有节点所需的最低总着色成本。

样本输入

5 1
1 2 1 2 4
1 2
1 3
2 4
3 5
0 0

样本输出

33

图示:

本题是一道合并类贪心,我们首先通过样例分析可知,一定要先染色完数值大的点显然要贪心

我们可以把大点向其父亲节点传递

不断找单位时间内值最大的点,即val[i]/tim[i]要最大

统计ans时,用当前点的值乘*其父亲节点的时间(时间已经累加到父亲节点上)

累加完当前节点的val之后记得要清零,防止重复累加

 我们要首先把所有点都染色一次因为我们初始时间为1在后面的统计中时间不会为1,所以其之前为时间1的值没有累加

code:

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3)
 3 const int N=1e5+10;
 4 using namespace std;
 5 int n,R,ans;
 6 int fa[N],val[N];
 7 double tim[N];
 8 inline int read(){
 9     int x=0,f=1;char ch=getchar();
10     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
11     while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
12     return x*f;
13 }
14 inline void write(int x){
15      char F[200];
16      int tmp=x>0?x:-x ;
17      if(x<0)putchar('-') ;
18      int cnt=0 ;
19         while(tmp>0)
20         {
21             F[cnt++]=tmp%10+'0';
22             tmp/=10;
23         }
24         while(cnt>0)putchar(F[--cnt]) ;
25 }
26 int main()
27 {
28     while(n=read(),R=read()){
29         ans=0;
30         memset(fa,0,sizeof fa);
31         memset(tim,0,sizeof tim);
32         memset(val,0,sizeof val);
33         if(n==0&&R==0)return 0;
34         for(int i=1;i<=n;i++){
35             val[i]=read();
36             ans+=val[i];
37             tim[i]=1;
38         }
39         for(int i=1;i<n;i++){
40             int a,b;
41             a=read(),b=read();
42             fa[b]=a;
43         }
44         for(int i=1;i<n;i++){
45             double sum=0;
46             int id;
47             for(int i=1;i<=n;i++){
48                 if((double(val[i]/tim[i]>sum))&&(i!=R)){
49                     sum=(double)val[i]/tim[i];
50                     id=i;
51                 }
52             }
53             for(int i=1;i<=n;i++){
54                 if(fa[i]==id){
55                     fa[i]=fa[id];
56                 }
57             }
58             ans+=tim[fa[id]]*val[id];
59             tim[fa[id]]+=tim[id];
60             val[fa[id]]+=val[id];
61             val[id]=0;
62         }
63         printf("%d
",ans);
64     }
65     return 0;
66 }

注意:因为有多组数据,所以要初始化为0存时间的数组类型要有double ,防止舍去了小数位,导致与标准数据相差1。

原文地址:https://www.cnblogs.com/nlyzl/p/11706920.html