poj 2054 Color a Tree

很有意思的一道贪心题,自己没想出来,理解了一下别人的思路

参考:http://www.cnblogs.com/yu-chao/archive/2012/02/19/2358565.html

    http://my.oschina.net/locusxt/blog/210536

题目大意:给你一颗树,树上每个节点都有自己的权值,现在要把这棵树上的所有节点染上颜色,每染一个节点需要一个单位的时间,染一个点的花费是该点的权值乘以当前时间(时间从1开始)。规定在染当前点之前,必须先染他的父亲节点,求最小的花费。

样例分析

Sample Input

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

表示这棵树有5个节点,根节点为1。接下来的5个数字代表每个点的权值,接下来的n-1行每行有两个数字v1,v2,代表v1是v2的父亲节点。

思路:刚拿到这道题的时候,我完全没有思路,因为每次染一个点之前必须把他父亲节点先染色,这样的话情况非常复杂。后来看了别人的报告,发现这道题的贪心策略非常特别首先,每个点分别属于一个集合,每个点集具有的属性是:1、点集中点的个数,下文称为nodeNum[i]。2、点集中所有点权值的和,下文中称为fact[i]。3、现在引入一个新的变量val[i],val[i]=fact[i]/nodeNum[i] 贪心策略就是,每次取val值最小的点进行染色。

现在的问题是取到该点时应该怎么染色,换句话说,应该如何求出答案。现在以样例进行说明:                             (1)首先取得集合5,由于要先染父节点,于是把5并入点集3,这样形成一个新的点集记为A集{3,5},将A集合的属性进行更新   ans+=nodeNum[3]*fact[5]=4     (这样可以保证在5之前染色的点所花费的时间考虑进来了)    A集合属性更新为nodeNum[A]=2,fact[A]=4+1=5 Val[A]=5.0/2;(2)接下来取得集合A,对于A,先把集合A并入集合1,这样形成一个新的点集B{1,3,5}  ans+=nodeNum[1]*fact[A]=9  B集合属性更新为nodeNum[B]=3,fact[B]=6,val[B]=6/3;(3)然后取得集合2,同理2并入B后形成新集合C{1,3,5,2}  ans+=nodeNum[B]*fact[2]=15  C集合属性更新为nodeNum[C]=4,fact[C]=8,val[C]=2(4)取得集合4,4并入C中形成新的集合D{1,3,5,2,4}  ans+=nodeNum[C]*fact[4]=23   nodeNum[D]=5,fact[D]=10显然,每个节点染色的时间都要比实际时间少了1,所以最后要加回来,即ans+=fact[D]=33

那么这样做为什么是正确的呢?根据参考,简单证明一下:要证明该结果正确,就是要证明:对于fact[i]/nodeNum[i](以下称为平均权值)最大的点,一旦他的父亲节点染色,他应当立即被染色。不妨假设平均权值最大的点为a,a的父亲节点为b,如果在b被染色之后,a没有立即被染色,即染色次序为 …b x1 x2 …… xn a … 也就是说,在b被染完色之后,a被染色之前,还有若干节点被染过色了。显然,如果我们能证明a与n互换位置之后的花费比不交换位置少,那么就可以证明a应该在b被染色后立即被染色。假设集合xn的总权值Wxn,点数Dxn,集合a的总权值为Wa,点数为Da。由于Wa/Da > Wxn / Dxn ,显然,Wxn*Da-Wa*Dxn<0,也就是说,在交换位置后,花费会减少,得证。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int C[2010],vis[2010],ans,dep;
int n,r;
int cnt,jihe[2010];
struct node
{
    int fa;
}nod[2010];
struct Set{
    int nodeNum;
    double val;
    int fact;
}ji[2010];
void Initial()
{
    for(int i=1;i<=n;i++){
        ji[i].nodeNum=1;
        ji[i].val=C[i];
        ji[i].fact=C[i];
        nod[i].fa=i;
    }
}
void update(int u)
{
    if(u==r){
        vis[u]=1;
        return ;
    }
    else{
        vis[u]=1;
        int v=nod[u].fa;
        if(ji[v].nodeNum==1){
            cnt++;
            if(jihe[u]!=0){
                for(int i=1;i<=n;i++){
                    if(i!=u && jihe[i]==jihe[u]){
                        jihe[i]=cnt;
                    }
                }
            }
            jihe[u]=cnt;
            jihe[v]=cnt;

        }
        else{
            if(jihe[u]!=0){
                for(int i=1;i<=n;i++){
                    if(i!=u && jihe[i]==jihe[u]){
                        jihe[i]=jihe[v];
                    }
                }
            }
            jihe[u]=jihe[v];
        }
        ans+=ji[u].fact*ji[v].nodeNum;
        ji[v].nodeNum+=ji[u].nodeNum;
        ji[v].fact+=ji[u].fact;
        ji[v].val=1.0*ji[v].fact/(1.0*ji[v].nodeNum);
        for(int i=1;i<=n;i++){
            if(jihe[i]==jihe[v]){
                ji[i]=ji[v];
            }
        }
        //cout<<"u "<<u<<" v "<<v<<" fact "<<ji[v].fact<<" val "<<ji[v].val<<" ans "<<ans<<endl;
    }
}
int main()
{
    while(~scanf("%d%d",&n,&r) && (n!=0||r!=0)){
        for(int i=1;i<=n;i++){
            scanf("%d",&C[i]);
        }
        Initial();
        for(int i=0;i<n-1;i++){
            int v1,v2;
            scanf("%d%d",&v1,&v2);
            nod[v2].fa=v1;
        }
        memset(vis,0,sizeof(vis));
        ans=0;
        int s;
        cnt=0;
        memset(jihe,0,sizeof(jihe));
        for(int i=1;i<=n;i++){
            int maxi,flag=0;
            double maxn=0;
            for(int j=1;j<=n;j++){
                if(!vis[j]){
                    if(ji[j].val>maxn){
                        maxi=j;
                        maxn=ji[j].val;
                        flag=1;
                    }
                }
            }
            if(!flag){
                break;
            }
            s=maxi;
            //cout<<"s "<<s<<endl;
            update(maxi);
        }
        ans+=ji[s].fact;
        cout<<ans<<endl;
    }
    return 0;
}

				
时间: 2024-07-29 11:20:14

poj 2054 Color a Tree的相关文章

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 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"

poj 2054 Color a Tree(贪心)

# include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int father[1010]; int next[1010];//当前集合的下个元素(包括i) int pre[1010];//当前集合的上个元素(包括i) int num[1010];//num[i]当前集合储存的点的个数(包括i) int vis[1010]; int sum[1010];//当前

POJ 2054 Color a Tree#贪心(难,好题)

题目链接 代码借鉴此博:http://www.cnblogs.com/vongang/archive/2011/08/19/2146070.html 其中关于max{c[fa]/t[fa]}贪心原则,此博有很好的解释:http://www.cnblogs.com/rainydays/p/3271277.html 在此引用其中几段话: 试想,如果没有父节点排在节点之前的限制,那么这个题目非常简单,只需要将结点按照权值从大到小排列即可.加上了这个限制之后,如果权值最大的那个节点一旦满足了条件(父节点

poj 2054 Color a Tree(贪婪)

# include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int father[1010]; int next[1010];//当前集合的下个元素(包含i) int pre[1010];//当前集合的上个元素(包含i) int num[1010];//num[i]当前集合储存的点的个数(包含i) int vis[1010]; int sum[1010];//当前

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求出这颗树的欧拉回路,以及每个点的

[ACM] POJ 2154 Color (Polya计数优化,欧拉函数)

Color Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7630   Accepted: 2507 Description Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of th

【POJ 3321】 Apple Tree (dfs重标号设区间+树状数组求和)

[POJ 3321] Apple Tree (dfs重标号设区间+树状数组求和) Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21966   Accepted: 6654 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. K

POJ 1046 Color Me Less 最详细的解题报告

题目来源:POJ 1046 Color Me Less 题目大意:每一个颜色由R.G.B三部分组成,D=Math.sqrt(Math.pow((left.red - right.red), 2)+ Math.pow((left.green - right.green), 2)+ Math.pow((left.blue - right.blue), 2)) 表示两个不同颜色的之间的距离(以left和right为例,left和right分别为两种不同的颜色),现给出16组目标颜色,剩下的为待匹配的颜