《算法竞赛进阶指南》0x07贪心 POJ2054 color the tree树的缩点与合并

题目链接:http://poj.org/problem?id=2054

贪心算法,思路参考yxc,涉及树的合并与缩点,将所有触发点构成的链全部缩进根节点即可得到最终的结果。证明:

《算法竞赛进阶指南》0x07贪心 POJ2054 color the tree树的缩点与合并

 《算法竞赛进阶指南》0x07贪心 POJ2054 color the tree树的缩点与合并

 代码如下:

#include<iostream>
using namespace std;

const int maxn= 1010;
struct Node{
    int fa,cnt,value;//维护父节点,结点数量以及缩点内的和,平均值 
    double avg; 
}p[maxn];

int root ,n;

int find(){//查找下一个均值最大点 
    double avg=0;
    int res=-1;
    for(int i=1;i<=n;i++){
        if(i!=root && p[i].avg>avg){
            avg=p[i].avg;
            res=i;
        }
    }
    return res;
}

int main(){
    while(cin>>n>>root && n && root){
        int ans=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&p[i].value);
            p[i].avg=p[i].value;
            p[i].cnt=1;
            ans+=p[i].value;//动态维护结果 
        }
        for(int i=0;i<n-1;i++){//输入边 
            int u,v;
            scanf("%d%d",&u,&v);
            p[v].fa=u;
        }    
        for(int i=0;i<n-1;i++){//每次合并两个点,合并n-1次收敛为一个点 
            int cur=find();
            int fa=p[cur].fa;
            ans+=p[fa].cnt*p[cur].value;
            p[cur].avg=-1;//表示当前点已经从图中删除,这个点将不会再使用
            p[fa].value+=p[cur].value;
            p[fa].cnt+=p[cur].cnt;
            p[fa].avg=(double)p[fa].value/p[fa].cnt; 
            for(int j=1;j<=n;j++){
                if(p[j].fa==cur)//将cur结点的子节点接到fa结点上 
                    p[j].fa=fa;
            } 
        }
        cout<<ans<<endl;
    }
}

相关推荐