hdu 3899(树形dp)

来源:互联网 发布:linux多线程编程 书籍 编辑:程序博客网 时间:2024/06/06 20:51

题目链接: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的根)。

 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         
View Code

 

0 0