http://poj.org/problem?id=3585
题目
有棵无根树,给出每一条边的最大流量,可以得到以点i为源时流过每个点的最大流量,可以随意调整i,求整个树所有的点的流量中的最大值。
题解
从每个点出发,发出的流量不好计算,因为有后效性。任意选一个根,如果从叶子出发,设dp[x]为以x为源时,x的流量,那么
x为叶子时dp[x]=0
考虑x的儿子t
如果不是叶子,$dp[x]+=min(dp[t],v(x,t)$
如果是叶子,$dp[x]+=v(x,t)$
然后还需要换根,设以x为根的流量是f[x]
每次换根
$f[t]=dp[t]+f[x]-min(dp[t],v(x,t)$
但是如果x在换了以后变成叶子也需要单独考虑
AC代码
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<cassert> #define REP(i,a,b) for(register int i=(a); i<(b); i++) #define REPE(i,a,b) for(register int i=(a); i<=(b); i++) #define PERE(i,a,b) for(register int i=(a); i>=(b); i--) using namespace std; #define MAXN 200007 int hd[MAXN], nxt[MAXN*2], to[MAXN*2], v[MAXN*2], en; int deg[MAXN]; int dp[MAXN], f[MAXN]; bool vis[MAXN]; int n; inline void adde(int a, int b, int c) { nxt[en]=hd[a]; hd[a]=en; to[en]=b; v[en]=c; en++; } void calc(int x) { dp[x]=0; vis[x]=1; for(int i=hd[x]; ~i; i=nxt[i]) { int t=to[i]; if(!vis[t]) { if(deg[t]==1) { dp[t]=0; vis[t]=1; dp[x] += v[i]; } else { calc(t); dp[x] += min(dp[t], v[i]); } } } } void dfs(int x) { vis[x]=1; for(int i=hd[x]; ~i; i=nxt[i]) { int t=to[i]; if(!vis[t]) { if(deg[x]==1) { f[t]=dp[t]+v[i]; } else { f[t]=dp[t]+min(f[x]-min(dp[t],v[i]), v[i]); } dfs(t); } } } int main() { int T; scanf("%d", &T); while(0<T--) { en=0; scanf("%d", &n); memset(hd+1, -1, sizeof(int)*n); memset(deg+1, 0, sizeof(int)*n); REP(i,1,n) { int a,b,c; scanf("%d%d%d", &a, &b, &c); adde(a,b,c); adde(b,a,c); deg[a]++, deg[b]++; } memset(vis+1, 0, sizeof(bool)*n); calc(1); memset(vis+1, 0, sizeof(bool)*n); f[1]=dp[1]; dfs(1); int ans=dp[1]; REPE(i,2,n) if(f[i]>ans) ans=f[i]; printf("%d ", ans); } }