树形DP HDU 3899

来源:互联网 发布:美少女战士 知乎 编辑:程序博客网 时间:2024/05/22 07:02

JLUCPC

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1390    Accepted Submission(s): 422


Problem Description
Dr. Skywind and Dr. Walkoncloud are planning to hold the annual JLU Collegiate Programming Contest. The contest was always held in the college of software in the past. However, they changed their minds and decided to find the most convenient location from all colleges this year.
Each college in JLU is located in one of the N (1 <= N <= 100,000) different locations (labeled as 1 to N) connected by N-1 roads. Any two colleges are reachable to each other. The Contest can be held at any one of these N colleges. Moreover, Road i connects college A_i and B_i (1 <= A_i <=N; 1 <= B_i <= N) and has length L_i (1 <= L_i <= 1,000). College i has T_i (0 <= T_i <= 1,000) teams participating in the contest.
When choosing the college to hold the Contest, Dr. Skywind wishes to minimize the inconvenience of the chosen location. The inconvenience of choosing college P is the sum of the distance that all teams need to reach college P (i.e., if the distance from college i to college P is 20, then the travel distance is T_i*20). Please help Dr. Skywind and Dr. Walkoncloud to choose the most convenient location for the contest.
 

Input
There are multiple test cases. For each case, the first line contains a single integer N, indicating the number of colleges. The next N lines describes T_1 to T_n. Then, each of the last N-1 lines will contain 3 integers, namely A_i, B_i and L_i.
 

Output
For each case, output the minimum inconvenience possible
 

Sample Input
31121 2 22 3 141001111 2 12 3 12 4 1
 

Sample Output
45
 

题意:一个图上有 n 个点 n - 1 条边,整个图联通,也就是一棵二叉树

树上每个点都有一个权值,每条边有一个权值,然后选定一个点u,其他所有点都要去到那个点,从v去到那个点的

花费 = val[v] * dis[u][v] ,这个点的总花费就是所有点到选定点的花费总和。

求这棵树上找一个点,是的总花费最小,输出最小花费

思路:

1.先一遍树形DP跑一遍树,从1开始,把 1 作为那个选定点,可以一边求出 点 1 的总花费,还能一边记录每个点的子树节点个数

2.第一遍跑完之后,再跑一遍树,这次把其余点的值算出来

比如 从根节点1开始 , 第一个儿子节点就是 2,那么以 2 作为选定点的时候,相对于他的父节点的总花费来说,他的所有儿子节点都多跑了 dis[1][2]这段距离,其余节点则少跑了 dis[1][2] 

设 sum 为整棵树的节点数,dp[u] 表示 u 节点的儿子节点数

那么 ans[v] = ans[u] - dp[v] * dis[u][v] + (sum - dp[v]) * dis[u][v] 

这样跑一遍树就能把所有点的总花费算出来,然后找最大值就可以了

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<vector> using namespace std;#define mem(a,x) memset(a,x,sizeof(a))#define ll long longconst int inf = (1)<<30;#define maxn 100005struct node{ll v,w;node(int v_,int w_) : v(v_),w(w_){}};ll ans[maxn],n,sum;ll dp[maxn],val[maxn];vector<node>vec[maxn];void add(ll u,ll v,ll w){vec[u].push_back(node(v,w));}void dfs1(ll u,ll pre,ll len){int sz = vec[u].size();for(int i = 0;i < sz;i++){ll v = vec[u][i].v;ll w = vec[u][i].w;if(v == pre)continue;ans[1] += (len + w) * val[v];dfs1(v,u,len + w);dp[u] += dp[v];}}void dfs2(ll u,ll pre){int sz = vec[u].size();for(int i = 0;i < sz;i++){ll v = vec[u][i].v;ll w = vec[u][i].w;if(v == pre)continue;ans[v] = ans[u] + (sum - dp[v]) * w - dp[v] * w;dfs2(v,u);}}void treedp(){dfs1(1,0,0);dfs2(1,0);}int main(){ll u,v,w;while(scanf("%lld",&n) != EOF){sum = 0;for(int i = 1;i <= n;i++){scanf("%lld",&dp[i]);val[i] = dp[i];sum += val[i];vec[i].clear();} for(int i = 1;i < n;i++){scanf("%lld %lld %lld",&u,&v,&w);add(u,v,w);add(v,u,w);}mem(ans,0);treedp();ll Ans = ans[1];for(int i = 2;i <= n;i++)if(Ans > ans[i])Ans = ans[i];printf("%lld\n",Ans);}return 0;}

原创粉丝点击