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);
}
}