yishujixiaoxiao 2020-06-16
题目链接:http://poj.org/problem?id=2054
贪心算法,思路参考yxc,涉及树的合并与缩点,将所有触发点构成的链全部缩进根节点即可得到最终的结果。证明:
代码如下:
#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; } }