把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

POJ3585 Accumulation Degree【换根dp】

题目传送门

题意

给出一棵树,树上的边都有容量,在树上任意选一个点作为根,使得往外流(到叶节点,叶节点可以接受无限多的流量)的流量最大。

分析

首先,还是从1号点工具人开始$dfs$,可以求出$dp[i]$为点$i$向它的子树中可以获得的最大流量。

接下来考虑换根,设$f[i]$是以$i$为根节点的答案(向它的所有根节点能够发射的最大流量之和)

 

考虑把根从$u$换到$v$,$v$自己子树内的答案$dp[v]$肯定是在$f[v]$之内的

经过了$u-v$这条边的答案就是$min(f[u]-min(w,dp[v]),w)$

加起来就是$f[v]=dp[v]+min(f[u]-min(w,dp[v]),w)$

理解一下:$f[u]-min(w,dp[v])$是减去红圈里的贡献,也就是$u$不往$v$里面流也产生的答案。要取$min(w,dp[v])$是因为$u$真正能流进$v$子树里的流量还要受到$w$的限制

相同地,把$v$当做根之后往$u$方向流的流量也会受到$w$的限制,所以也要取$min$。

 

另外,特别地,还有这种情况:

 

 

(这种情况真的好难想到的说)

这种情况的话,答案就直接是$f[v]=dp[v]+w$

然而用上面的式子的话,$f[u]-min(w,dp[v])=0$,变成$f[v]=dp[v]$,是不成立的。所以需要特判一下。

然后就做

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 #include<cstring>
 5 using namespace std;
 6 #define N 200005
 7 #define ll long long
 8 #define INF 0x3f3f3f3f
 9 int n,ans;
10 int dp[N],f[N];
11 vector<pair<int,int> >G[N];
12 int rd()
13 {
14     int f=1,x=0;char c=getchar();
15     while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
16     while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
17     return f*x;
18 }
19 void dfs(int u,int p)
20 {
21     int tmp=0;
22     for(int i=0;i<G[u].size();i++)
23     {
24         int v=G[u][i].first,w=G[u][i].second;
25         if(v==p) continue;
26         dfs(v,u);
27         tmp+=min(dp[v],w);
28     }
29     if(tmp) dp[u]=tmp;
30     return ;
31 }
32 void dfs2(int u,int p)
33 {
34     ans=max(ans,f[u]);
35     for(int i=0;i<G[u].size();i++)
36     {
37         int v=G[u][i].first,w=G[u][i].second;
38         if(v==p) continue;
39         if(G[u].size()==1)
40         {
41             f[v]=dp[v]+w;
42             dfs2(v,u);
43         }
44         else
45         {
46             f[v]=dp[v]+min(w,f[u]-min(w,dp[v]));
47             dfs2(v,u);
48         }
49     }
50 }
51 int main() 
52 {
53     int T=rd();
54     while(T--)
55     {
56         n=rd();
57         if(n==0)
58         {//特判 
59             puts("0");
60             continue;
61         }
62         ans=0;
63         memset(dp,INF,sizeof(dp));
64         for(int i=1;i<=n;i++)
65             G[i].clear();
66         for(int i=1;i<n;i++)
67         {
68             int u=rd(),v=rd(),w=rd();
69             G[u].push_back(make_pair(v,w));
70             G[v].push_back(make_pair(u,w));
71         }
72         dfs(1,-1);
73         for(int i=1;i<=n;i++)
74             if(dp[i]==INF)
75                 dp[i]=0;//叶节点
76         f[1]=dp[1];
77         dfs2(1,-1);
78         printf("%d\n",ans); 
79     }
80 }
Code

 

完啦。

 

 

 

posted @ 2019-11-06 11:21  Starlight_Glimmer  阅读(145)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end