標籤:nbsp bre 思路 \n pac namespace names 最大的 怎樣
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1055
題意:給一棵樹塗色,這棵樹的每個節點都有自己的價值Ci,塗色的原則是只由這個節點的父節點塗色之後才能塗色(就是從根節點開始塗色)。
每次塗色用時1s,每個節點的塗色花費是Ci*Fi(Fi是從最開始到塗色到這個節點所花的時間)。對這棵樹塗色的總塗色花費為sum,
求怎樣塗色才能使sum最小。
思路:
結論:對於一個非根節點,它具有最大的權值,只有先訪問完它的父節點再訪問它才能使總花費最小。
1、建立一個結構體,c表示節點價值,fa表示父節點,t表示耗時,ans為總花費,初始化為sum(ci),表示每個節點自己塗色。
2、找到最大的非根節點m,然後找到它的父節點p,將m與p合并。ans+=vc[m].c*vc[p].t,表示從m到p這段路上的代價,然後
vc[p].c+=vc[m].c; vc[p].t+=vc[m].t; vc[p].w=1.0*vc[p].c/vc[p].t;
3、重複n-1次,因為有n個節點,n-1後合并為1個節點。
#include<iostream>#include<cstdio>#include<string>using namespace std;struct Node{ int fa,c,t; double w;};Node vc[10010];int fd(int n,int r){ int i,j,p; double mx=-1.0; for(i=1;i<=n;i++) { if(i!=r&&vc[i].w>mx) { mx=vc[i].w; p=i; } } return p;}int main(void){ int n,r,i,j,ans,p,m,x,y; while(~scanf("%d %d",&n,&r)) { if(n==0&&r==0) break; ans=0; for(i=1;i<=n;i++) { scanf("%d",&vc[i].c); vc[i].t=1; vc[i].w=vc[i].c; ans+=vc[i].c; } for(i=1;i<n;i++) { scanf("%d %d",&x,&y); vc[y].fa=x; } for(i=1;i<n;i++) { m=fd(n,r); p=vc[m].fa; vc[m].w=0; ans+=vc[m].c*vc[p].t; for(j=1;j<=n;j++) if(vc[j].fa==m) vc[j].fa=p; vc[p].c+=vc[m].c; vc[p].t+=vc[m].t; vc[p].w=1.0*vc[p].c/vc[p].t; } printf("%d\n",ans); } return 0;}
hdu-1055(貪心)