HDU 1055 Color a Tree

题目:Color a Tree

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1055

题意:给一棵树,要给树上每一个结点染色,第i 个结点染色需要代价为:t * w[i] (t 表示i 结点是第几个染色的),还有一个前提是:要给i 结点染色,必须先给i 结点的父结点染色(根结点随便染)。

思路:

  贪心。

  假定当前未染色的结点中权值最大的是A结点,如果A结点上方都染完色,那么现在一定是对A结点进行染色。

  理解如下:

  假设在上述情况下先对其他结点染色,在t 时刻后才轮到A,那么到t 时刻为止,消耗代价为:t1 * w1 + t2 * w2 + ... + tn * wn + t * wA,因为A在初始就具备了染色条件,并且 t = tn + 1,wA > wn,所以A可以往前挪一位,即t1 * w1 + t2 * w2 + ... + tn * wA + t * wn 必然更优,这点很好理解(wa 可以分成 wn + x),而继续上面的操作,最终wa 可以挪到最前面,所以上述情况下,一定是对A结点进行染色。

  现在问题就是当A结点不是根结点的时候(即A的父结点还没有染色),可以想象,如果等会A的父结点染完色,那么接下来一定是轮到A了(A的父结点染色后,A就是第一种情况了),既然他们的染色顺序一定相邻,所以两个结点可以结合在一起。把他们看作一个新的结点,而新结点的权值可以用他们的平均值代替,假设等会在t时刻轮到他们染色,那么消耗代价本来为t * wfa + (t + 1) * wa,所以ans 可以先加上wa,那么等会遇到这个结点时,就可以ans += t * (w[fa] + w[a]),然后t+=2。

  因此,结点保存3个值:sum(w总和),num(合并的数量),w(找最大标志)。对于为什么可以用平均值作为新结点的权值也很好理解了,因为他后面的消耗代价为t * sum 即 t * wfa + t*wa(注意:加完这个,t要+2,而不是普通的+1),他们之间是不能中断的,那么他们两个放到什么位置就取决于他们的平均值了。  (即tn*wn + (tn+1)*w和 tn * w + (tn+2)*wn 的对比了)

AC代码:

  1 #include<stdio.h>
  2 #include<vector>
  3 using namespace std;
  4 #define N 1010
  5 #define LL long long
  6 struct Node
  7 {
  8   int num,sum;
  9   double w;
 10   Node(){}
 11   bool operator < (Node b) const
 12   {
 13     return w < b.w;
 14   }
 15 }v[N];
 16
 17 int n;
 18 int fa[N];
 19 int f[N];
 20
 21 int find(int x)
 22 {
 23   int p=x;
 24   while(p!=fa[p]) p=fa[p];
 25   int q;
 26   while(fa[x]!=p)
 27   {
 28     q=fa[x];
 29     fa[x]=p;
 30     x=q;
 31   }
 32   return p;
 33 }
 34
 35 bool vis[N];
 36 int find()
 37 {
 38   int p = -1;
 39   double maxt = 0;
 40   for(int i=1;i<=n;i++)
 41   {
 42     if(vis[i]==1) continue;
 43     if(v[i].w > maxt)
 44     {
 45       maxt = v[i].w;
 46       p = i;
 47     }
 48   }
 49   return p;
 50 }
 51
 52 int main()
 53 {
 54   int r,x,y;
 55   while(~scanf("%d%d",&n,&r))
 56   {
 57     if(n==0 && r==0) break;
 58     LL ans = 0;
 59     for(int i=1;i<=n;i++)
 60     {
 61       fa[i] = i;
 62       vis[i] = 0;
 63       scanf("%d",&v[i].sum);
 64       v[i].num = 1;
 65       v[i].w = 1.0 * v[i].sum / v[i].num;
 66     }
 67     vis[0] = 1;
 68     fa[0] = 0;
 69     f[r]=0;
 70     for(int i=1;i<n;i++)
 71     {
 72       scanf("%d%d",&x,&y);
 73       f[y]=x;
 74     }
 75     int t = 1;
 76     while(1)
 77     {
 78       int p = find();
 79
 80       if(p==-1) break;
 81       if(vis[find( f[p] ) ] == 1)
 82       {
 83         ans += t * v[p].sum;
 84         t += v[p].num;
 85         vis[p] = 1;
 86       }
 87       else
 88       {
 89         vis[p]=1;
 90         int fp = find(f[p]);
 91         ans += v[p].sum * v[fp].num;
 92         v[fp].num += v[p].num;
 93         v[fp].sum += v[p].sum;
 94         v[fp].w = 1.0 * v[fp].sum / v[fp].num;
 95         fa[p] = fp;
 96       }
 97     }
 98     printf("%I64d\n",ans);
 99   }
100   return 0;
101 }
102
103 /*
104 6 1
105 1 2 1 2 4 1
106 1 2
107 1 3
108 2 4
109 3 5
110 4 6
111
112 39
113 */
时间: 2024-08-06 17:06:41

HDU 1055 Color a Tree的相关文章

hdu 4603 Color the Tree 2013多校1-4

这道题细节真的很多 首先可以想到a和b的最优策略一定是沿着a和b在树上的链走,走到某个点停止,然后再依次占领和这个点邻接的边 所以,解决这道题的步骤如下: 预处理阶段: step 1:取任意一个点为根节点,找出父子关系并且对这个树进行dp,求出从某个节点出发往下所包含的所有边的权值总和  复杂度O(n) step 2:从tree dp 的结果中计算对于某个节点,从某条边出发所包含的边的综合,并且对其从大到小进行排序 复杂度O(n*logn) step 3:dfs求出这颗树的欧拉回路,以及每个点的

hdu 4603 Color the Tree

这道题细节真的非常多 首先能够想到a和b的最优策略一定是沿着a和b在树上的链走,走到某个点停止,然后再依次占据和这个点邻接的边 所以,解决这道题的过程例如以下: 预处理阶段: step 1:取随意一个点为根节点.找出父子关系而且对这个树进行dp.求出从某个节点出发往下所包括的全部边的权值总和  复杂度O(n) step 2:从tree dp 的结果中计算对于某个节点.从某条边出发所包括的边的综合.而且对其从大到小进行排序 复杂度O(n*logn) step 3:dfs求出这颗树的欧拉回路,以及每

hdu 1055 &amp; poj 2054 Color a Tree 树&amp;贪心 找最大费用点和父节点合并

Color a Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 7144 Accepted: 2458 Description Bob is very interested in the data structure of a tree. A tree is a directed graph in which a special node is singled out, called the "root"

HDU 1556 Color the ball 线段树更新区间查点

点击打开链接 Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9120    Accepted Submission(s): 4665 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽

hdu 5378 Leader in Tree Land(dp+逆元)

题目链接:hdu 5378 Leader in Tree Land 问题可以理解成N个节点的树,有K个ministers的概率,最后乘上N!.每个节点为ministers的概率即为1 / son(以该节点为根节点的子树包含的节点个数),同样不为ministers的概率为(son-1)/son.所以没有必要考虑树的结构,直接根句子节点的个数转移dp[i][j] dp[i][j] = dp[i-1][j-1] * 1 / son[u] dp[i][j] = dp[i-1][j] * (son[u]-

poj 2054 Color a Tree 据说是贪心

Color a Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 7112   Accepted: 2438 Description Bob is very interested in the data structure of a tree. A tree is a directed graph in which a special node is singled out, called the "root&qu

HDU 4896 Minimal Spanning Tree(矩阵快速幂)

题意: 给你一幅这样子生成的图,求最小生成树的边权和. 思路:对于i >= 6的点连回去的5条边,打表知907^53 mod 2333333 = 1,所以x的循环节长度为54,所以9个点为一个循环,接下来的9个点连回去的边都是一样的.预处理出5个点的所有连通状态,总共只有52种,然后对于新增加一个点和前面点的连边状态可以处理出所有状态的转移.然后转移矩阵可以处理出来了,快速幂一下就可以了,对于普通的矩阵乘法是sigma( a(i, k) * b(k, j) ) (1<=k<=N), 现在

hdu 2489 Minimal Ratio Tree(dfs枚举 + 最小生成树)~~~

题目: 链接:点击打开链接 题意: 输入n个点,要求选m个点满足连接m个点的m-1条边权值和sum与点的权值和ans使得sum/ans最小,并输出所选的m个点,如果有多种情况就选第一个点最小的,如果第一个点也相同就选第二个点最小的........ 思路: 求一个图中的一颗子树,使得Sum(edge weight)/Sum(point weight)最小~ 数据量小,暴力枚举~~~~~dfs暴力枚举C(M,N)种情况. 枚举出这M个点之后,Sum(point weight)固定,进行prim或者K

Bestcoder round #65 &amp;&amp; hdu 5593 ZYB&#39;s Tree 树形dp

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 354    Accepted Submission(s): 100 Problem Description ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no m