码迷,mamicode.com
首页 > 其他好文 > 详细

poj 2054 Color a Tree

时间:2015-07-11 16:40:05      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:

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

参考: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;
}
View Code

 



 

poj 2054 Color a Tree

标签:

原文地址:http://www.cnblogs.com/Scale-the-heights/p/4638686.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!