Codeforces 294E Shaass the Great
2013-07-23 19:42 bootstar 阅读(357) 评论(0) 编辑 收藏 举报树形DP。由于n只有5000,可以直接枚举边。
枚举边,将树分成两个子树,然后从每个子树中选出一个点分别为u,v,那么答案就是:
子树1中任意两点距离总和+子树2中任意两点距离总和+子树1中任意一点到u的距离和*子树2的节点个数+子树2中任意一点到v的距离和*子树1的节点个数+子树1的节点个数*子树2的节点个数*当前枚举边的权值。
当枚举的边一定时,那么要选取的点就是子树中到所有点的距离总和最小的点。对树进行dfs,同时记录子树的节点个数,所有孩子节点到当前根节点的距离总和,以及当前子树中任意两点距离和。然后在进行dfs求解到该子树中所有点距离和最小的点。
1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #include <algorithm> 5 using namespace std; 6 typedef long long LL; 7 typedef pair <int, int> pii; 8 #define maxn 5005 9 #define INF 0x3f3f3f3f3f3f3f3fll 10 11 int f[maxn], h[maxn], w[maxn]; 12 vector<pii> g[maxn]; 13 int son[maxn]; 14 LL d[maxn], s[maxn]; 15 16 void dfs(int v, int rt){ 17 son[v] = 0, d[v] = 0, s[v] = 0; 18 for(int i = 0; i != g[v].size(); i ++){ 19 int u = g[v][i].first; 20 if(u==rt) continue; 21 dfs(u, v); 22 s[v] += s[u] + d[u]*son[v] + d[v]*son[u] + (LL)son[u] * son[v] * g[v][i].second; 23 d[v] += d[u] + (LL)son[u] * g[v][i].second; 24 son[v] += son[u]; 25 } 26 son[v] ++; 27 s[v] += d[v]; 28 } 29 void dfsw(int v, int rt, LL &minn){ 30 minn = min(d[v], minn); 31 for(int i = 0; i != g[v].size(); i ++){ 32 int u = g[v][i].first; 33 if(u==rt) continue; 34 d[u] = d[u] + (d[v] - d[u] - (LL)son[u]*g[v][i].second) + (LL)(son[v] - son[u])*g[v][i].second; 35 son[u] = son[v]; 36 dfsw(u, v, minn); 37 } 38 } 39 int main(){ 40 //freopen("test.in", "r", stdin); 41 for(int n; scanf("%d", &n)!=EOF; ){ 42 for(int i = 1; i <= n; i ++){ 43 g[i].clear(); 44 } 45 for(int i = 1, x, y, z; i < n; i ++){ 46 scanf("%d%d%d", &x, &y, &z); 47 f[i] = x, h[i] = y, w[i] = z; 48 g[x].push_back(make_pair(y, z)); 49 g[y].push_back(make_pair(x, z)); 50 } 51 LL ans = INF, minn = INF, sum = 0; 52 for(int i = 1; i < n; i ++){ 53 minn = INF; 54 dfs(f[i], h[i]); 55 dfsw(f[i], h[i], minn); 56 sum = 0; 57 sum = (n - son[f[i]]) * minn + s[f[i]]; 58 minn = INF; 59 dfs(h[i], f[i]); 60 dfsw(h[i], f[i], minn); 61 sum = sum + (n - son[h[i]]) * minn + s[h[i]] + (LL)son[f[i]]*son[h[i]]*w[i]; 62 ans = min(ans, sum); 63 } 64 printf("%I64d\n", ans); 65 } 66 return 0; 67 }