POJ - 3585 树上最大流 换根法

题意:给出一棵树,边上有容量限制,求以任一点作为根和源点,叶子作为汇点的最大流的最大值

首先上网络流等于找死

树形DP可以\(O(n)\)求出以某点\(u\)为根的最大流,只需设\(f[u]=\sum min(cap_{u→v},f[v])\),
这是一个自底向上的过程
其中存在\(min\)是因为\(f[v]\)不包含连向\(u\)的边,要保证合法增广,
注意如果\(v\)为叶子则直接加上\(cap_{u→v}\)

此时我们也得知\(f[v]\)是以v为根的子树的最大流

那么换根后显然以\(v\)为整棵树的根时,最大流\(g[v]\)至少包含\(f[v]\),还有指向父亲\(u\)部分的贡献,这部分的贡献有原式可以比较得出为\(min(cap_{u→v},g[u]-min(cap_{u→v},f[v]))\),同理叶子需要特判,且\(f[root]=g[root]\)
这是一个自顶向下的过程

由此只需\(O(n)\)扫两遍就能得出任一点作为源点的最大流

另外由于POJ过于垃圾请交C++

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rrep(i,j,k) for(int i=j;i>=k;i--)
#define erep(i,u) for(int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
using namespace std;
const int MAXN = 2e5+11;
const int MOD = 1e9+7;
typedef long long ll;
unsigned int xjb=2333333;
int Rand(){
    return (xjb=xjb*12345+23333)%MOD+1;
}
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int to[MAXN<<1],nxt[MAXN<<1],cost[MAXN<<1],head[MAXN],tot;
int deg[MAXN];
void add(int u,int v,int w){
    to[tot]=v;
    cost[tot]=w;
    nxt[tot]=head[u];
    head[u]=tot++;
}
void init(){
    memset(head,-1,sizeof head);
    tot=0;
}
ll f[MAXN],g[MAXN],n;
void DP(int u,int fa){
    f[u]=0;
    for(int i=head[u];~i;i=nxt[i]){
        int v=to[i];
        ll w=cost[i];
        if(v==fa) continue;
        DP(v,u);
        if(deg[v]==1) f[u]+=w;
        else f[u]+=min(w,f[v]);
    }
}
void dfs(int u,int fa){
    for(int i=head[u];~i;i=nxt[i]){
        int v=to[i];
        ll w=cost[i];
        if(v==fa) continue;
        g[v]=f[v]; 
        if(deg[u]==1) g[v]+=w;
        else g[v]+=min(w,g[u]-min(w,f[v]));
        dfs(v,u);
    }
}
int main(){
    int T=0; cin>>T;
    while(T--){
        init();
        memset(deg,0,sizeof deg);
        n=read();
        rep(i,1,n-1){
            int u=read();
            int v=read();
            int w=read();
            add(u,v,w);
            add(v,u,w);
            deg[u]++;
            deg[v]++;
        }
        DP(1,0);g[1]=f[1];
        dfs(1,0);
        ll ans=0;
        rep(i,1,n) ans=max(ans,g[i]);
        println(ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/caturra/p/9363595.html