POJ3847:Moving to Nuremberg

——一棵树,有边权,有一些点有点权,其余点点权为0。要求一个点,使得该点到其他点的边权和*点权的总和最小。

——dp……大概算dp吧

——url:http://poj.org/problem?id=3847

————————————————————————————————————————————————————————————————————

任选一个点作为根,将无根树变成有根树。

预处理出(所有有点权的点到根的边权和*点权)的和D[ROOT]

预处理出以每个点u为根的子树中所有点的frequency的和F[U]

一遍dfs,求出每个点的D值

D[U]=Segma(W*(sum-2*F[V]))   V为U的儿子,W为(u,v)的边权。

——————————————————————————

简要说明:

若当前已知一个点U的D值,如何求出其儿子V的D值?

即将当前点从u往下移到v

此时有些点到v的D值=这些点到u的D值+w*2*f  ,另这些点为第一类点。

那么第二类点到v的D值=点到u的D值-w*2*f 。

其实第二类点全部都是v的后继结点,而第一类点就是除了v和其后继结点的点。

View Code
 1 #include<stdio.h>
2 #include<memory.h>
3 #define N 50010
4 #define oo 1000000000000000LL
5 int n, m, num, cas, u, v, i, j;
6 long long ans, sum, w;
7 int head[N], nxt[N * 2], ev[N*2],temp[N];
8 long long frequency[N], f[N], ew[N * 2], dp[N],dis[N];
9 void addedge(int u, int v, long long w)
10 {
11 nxt[++num] = head[u];
12 head[u] = num;
13 ev[num] = v;
14 ew[num] = w;
15 }
16 void readin()
17 {
18 memset(head, -1, sizeof(head));
19 memset(frequency, 0, sizeof(frequency));
20 num = -1;
21 scanf("%d", &n);
22 for (i = 0; i < n - 1; i++)
23 {
24 scanf("%d%d%lld", &u, &v, &w);
25 addedge(u, v, w);
26 addedge(v, u, w);
27 }
28 sum = 0;
29 scanf("%d", &m);
30 for (i = 0; i < m; i++)
31 {
32 scanf("%d%lld", &u, &w);
33 frequency[u] = w;
34 sum += frequency[u];
35 }
36 }
37 void pre_dfs(int father, int u)
38 {
39 int i;
40 f[u] = 0;
41 dis[u] = 0;
42 for (i = head[u]; i != -1; i = nxt[i])
43 if (ev[i] != father)
44 {
45 pre_dfs(u, ev[i]);
46 dis[u] += dis[ev[i]] + 2 * ew[i] * f[ev[i]];
47 f[u] += f[ev[i]];
48 }
49 f[u] += frequency[u];
50 }
51 void dfs(int father, int u, long long dis)
52 {
53 int i;
54 dp[u] = dis;
55 if (dp[u] < ans)
56 ans = dp[u];
57 for (i = head[u]; i != -1; i = nxt[i])
58 if (father != ev[i])
59 dfs(u, ev[i], dis + 2 * ew[i] * (sum - 2 * f[ev[i]]));
60 }
61 void solve()
62 {
63 pre_dfs(1, 1);
64 ans = oo;
65 dfs(1, 1, dis[1]);
66 printf("%lld\n", ans);
67 for (j = -1, i = 1; i <= n; i++)
68 if (dp[i] == ans)
69 temp[++j] = i;
70 for (i = 0; i <= j; i++)
71 if (i != j)
72 printf("%d ", temp[i]);
73 else
74 printf("%d\n", temp[i]);
75 }
76 int main()
77 {
78 scanf("%d", &cas);
79 while (cas--)
80 {
81 readin();
82 solve();
83 }
84 return 0;
85 }

  

posted on 2011-09-08 16:08  风也轻云也淡  阅读(376)  评论(0编辑  收藏  举报