题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3899
思路:num[u]表示u以及u的子树的队伍数的总和,dist[u]表示u到根节点的距离,dp[u]表示以u为根时的总花费。我们可以先做一次dfs算出树上所有点到根节点(1)的花费总和,然后同时计算出num[],然后就是又一次dfs算出以每个点为根的话费,这里有dp[v]=dp[u]+(sum-num[v])*w-num[v]*w(其中u是v的根)。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 #define MAXN 100100 8 typedef long long LL; 9 #pragma comment(linker, "/STACK:1024000000,1024000000") 10 11 struct Edge{ 12 int v,w; 13 Edge(int vv,int ww):v(vv),w(ww){} 14 }; 15 16 int n; 17 int num[MAXN],sum; 18 LL dp[MAXN],dist[MAXN],ans; 19 vector<vector<Edge> >G; 20 21 void dfs1(int u,int father) 22 { 23 for(int i=0;i<G[u].size();i++){ 24 int v=G[u][i].v,w=G[u][i].w; 25 if(v==father)continue; 26 dist[v]=dist[u]+w; 27 ans+=(LL)num[v]*dist[v]; 28 dfs1(v,u); 29 num[u]+=num[v]; 30 } 31 } 32 33 void dfs2(int u,int father) 34 { 35 for(int i=0;i<G[u].size();i++){ 36 int v=G[u][i].v,w=G[u][i].w; 37 if(v==father)continue; 38 dp[v]=dp[u]+(LL)(sum-num[v])*w-(LL)num[v]*w; 39 dfs2(v,u); 40 } 41 } 42 43 44 int main() 45 { 46 int u,v,w; 47 while(~scanf("%d",&n)){ 48 G.clear(); 49 G.resize(n+2); 50 sum=0; 51 for(int i=1;i<=n;i++){ 52 scanf("%d",&num[i]); 53 sum+=num[i]; 54 } 55 for(int i=1;i<n;i++){ 56 scanf("%d%d%d",&u,&v,&w); 57 G[u].push_back(Edge(v,w)); 58 G[v].push_back(Edge(u,w)); 59 } 60 dist[1]=0; 61 ans=0; 62 dfs1(1,-1); 63 memset(dp,0,sizeof(dp)); 64 dp[1]=ans; 65 dfs2(1,-1); 66 // cout<<ans<<"**"<<endl; 67 for(int i=2;i<=n;i++){ 68 ans=min(ans,dp[i]); 69 // cout<<dp[i]<<"***"<<endl; 70 } 71 printf("%I64d\n",ans); 72 } 73 return 0; 74 } 75 76