zoukankan      html  css  js  c++  java
  • [Luogu] UVA1205 Color a Tree

    (Link)

    Description

    有一棵树,需要给其所有节点染色,每个点染色所需的时间是一样的,都是(1)。给每个点染色,还有一个开销为“当前时间(×c_i)”,(c_i)是每个节点的一个权值。(当前时间是染完这个节点的时间)
    染色还有另一个约束条件,要染一个点必须要先染好其父节点,所以第一个染的点是根节点。
    求最小开销。

    Solution

    神奇的贪心题。

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

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

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

    (2.)(z+2x+3y),先染(z),再染(x,y)

    比较两数大小,也就是比较(frac{(x+y)}{2})(z)

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

    然后缩点可以用并查集。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int n, rt, res, a[1005], c[1005], t[1005], f[1005], fa[1005], vis[1005];
    
    double val[1005];
    
    int read()
    {
    	int x = 0, fl = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
    	return x * fl;
    }
    
    int gf(int x)
    {
    	return x == fa[x] ? x : fa[x] = gf(fa[x]);
    }
    
    void merge(int x, int y)
    {
    	fa[x] = y;
    	return;
    }
    
    void work()
    {
    	int pos; double mx = 0;
    	for (int i = 1; i <= n; i ++ )
    		if (i != rt && val[i] > mx && !vis[i])
    			mx = val[i], pos = i;
    	int ff = gf(f[pos]);
    	vis[pos] = 1;
    	res += c[pos] * t[ff] + a[pos];
    	t[ff] += t[pos]; c[ff] += c[pos]; val[ff] = (double)(c[ff]) / (double)(t[ff]);
    	//这一步非常重要。t和val的处理都很好理解,但c为什么也要累加呢?我的理解是这样处理c[x],其实就是x和x的子树中被合并的点权之和。这样上面更新res的时候才是对的。(因为一个点的时间增加,它的子树内所有的点的时间也都会增加)
      	merge(pos, ff);
    	return;
    }
    
    int main()
    {
    	while (1)
    	{
    		n = read(), rt = read();
    		f[rt] = 0;
    		memset(vis, 0, sizeof(vis));
    		if ((!n) && (!rt)) break;
    		for (int i = 1; i <= n; i ++ ) a[i] = read(), c[i] = a[i];
    		res = c[rt];
    		for (int i = 1; i <= n - 1; i ++ )
    		{
    			int x = read(), y = read();
    			f[y] = x;
    		}
    		for (int i = 1; i <= n; i ++ ) fa[i] = i, t[i] = 1, val[i] = c[i];
    		for (int i = 1; i <= n - 1; i ++ ) work();
    		printf("%d
    ", res);
    	}
    	return 0;
    }
    
  • 相关阅读:
    less和vim中使用正则表达式搜索
    正则表达式解英语单词字谜
    正则表达式中的Quantifiers
    grep正则表达式(二)
    grep正则表达式(一)
    Linux中的touch命令总结(一)
    find命令进阶(三):xargs
    find命令进阶(二):对找到的文件执行操作exec
    构造函数
    Bean的生命周期
  • 原文地址:https://www.cnblogs.com/andysj/p/14032893.html
Copyright © 2011-2022 走看看