【POJ3585】Accumulation Degree

有关树形dp+二次扫描与换根法

首先我们读入数据,用邻接表存储,并记录每一个点相连的边的数量。

我们不妨先暂时假定节点1为树根,定义d[x]表示在以x为根的子树当中最大的流量,显然得出状态转移方程

d[x]=∑min(d[y],c(x,y))  其中y∈son(x).

求出了d数组,我们考虑“二次扫描与换根法”,定义f[x]表示以x为这棵树的根时的最大流量。那么f[x]包括两部分:

  1. 以x为根,流向x的儿子们的流量,这部分的答案即为d[x]
  2. 从x流向x的父亲,进而流向其他的节点,这一部分的答案我们可以这样考虑:把x作为根时流量为f[x],从x流向x的儿子y的流量为min(d[y],c(x,y)),所以x的流量减去这部分流量得到的差值就是剩余部分的流量。于是,把y作为原点,从y流向x的流量就是这个差值与c(x,y)取最小值的结果。因此不难得出状态转移方程f[y]=d[y]+min(f[x]-min(d[y],c(x,y)),c(x,y))
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <stack>
 4 #include <algorithm>
 5 #include <queue>
 6 #include <cstring>
 7 #include <cmath>
 8 #define maxx 200005
 9 using namespace std;
10 int head[maxx],to[maxx<<1],w[maxx<<1],_next[maxx<<1];
11 int d[maxx];
12 int cnt=0;
13 int deg[maxx];
14 void addEdge(int x,int y,int _w) {
15     to[++cnt]=y,w[cnt]=_w,_next[cnt]=head[x],head[x]=cnt;
16     to[++cnt]=x,w[cnt]=_w,_next[cnt]=head[y],head[y]=cnt;
17 }
18 int n;
19 void dfs1(int root,int fa) {
20     d[root]=0;
21     for(int i=head[root]; i; i=_next[i]) {
22         int v=to[i];
23         if(v==fa)
24             continue;
25         dfs1(v,root);
26         if(deg[v]==1)
27             d[root]+=w[i];
28         else
29             d[root]+=min(w[i],d[v]);
30     }
31 }
32 int f[maxx];
33 void dfs2(int root,int fa) {
34     for(int i=head[root]; i; i=_next[i]) {
35         int v=to[i];
36         if(v==fa)
37             continue;
38         if(deg[root]==1)
39             f[v]=d[v]+w[i];
40         else
41             f[v]=d[v]+min(f[root]-min(w[i],d[v]),w[i]);
42         dfs2(v,root);
43     }
44 }
45 void init() {
46     memset(head,0,sizeof(head));
47     memset(f,0,sizeof(f));
48     memset(deg,0,sizeof(deg));
49     cnt=0;
50 }
51 int main() {
52     int t;
53     cin>>t;
54     while(t--) {
55         cin>>n;
56         int x,y,w;
57         init();
58         for(int i=1; i<n; i++) {
59             scanf("%d%d%d",&x,&y,&w);
60             deg[x]++;
61             deg[y]++;
62             addEdge(x,y,w);
63         }
64         if(n==0||n==1) {
65             cout<<0<<endl;
66             continue;
67         }
68         int root=1;
69         dfs1(root,0);
70         f[root]=d[root];
71         dfs2(root,0);
72         int ans=0;
73         for(int i=1; i<=n; i++)
74             ans=max(ans,f[i]);
75         cout<<ans<<endl;
76     }
77     return 0;
78 }
AC Code
原文地址:https://www.cnblogs.com/shl-blog/p/10726875.html