POJ 3585 Accumulation Degree 题解

题面

一句话题意:找一个点使得,使得从这个点出发作为源点,发出的流量最大,输出这个最大的流量

这道题是换根法+二次扫描的模板;

首先若确定1为原点,那么可以写出dp方程:当v的度是1时, g[u]+=g[v];否则g[u]+=min(g[v],star[i].w);

但以上仅仅是有原点的做法,那么如果没有原点就只能是N^2了吗?当然不仅可能;

我们从上到下开始dfs,设f[i]表示以i为根所能得到的最大值,那么显然:f[1]=g[1];

然后分两种情况:如果u的度是1,那么f[v]=g[u]+star[i].w;

                             否则,f[v]=g[v]+min(star[i].w,f[u]-min(g[v],star[i].w));

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n;
struct littlestar{
    int to;
    int nxt;
    int w;
}star[1000010];
int head[1000010],cnt;
void add(int u,int v,int w)
{
    star[++cnt].to=v;
    star[cnt].w=w;
    star[cnt].nxt=head[u];
    head[u]=cnt;
}
int g[500010],f[500010];
int du[500010];
void dp(int u,int fa)
{
    g[u]=0;
    for(int i=head[u];i;i=star[i].nxt){
        int v=star[i].to;
        if(v==fa) continue;
        dp(v,u);
        if(du[v]==1){
            g[u]+=star[i].w;
        }
        else{
            g[u]+=min(g[v],star[i].w);
        }
    }
}
void dfs(int u,int fa)
{
    for(int i=head[u];i;i=star[i].nxt){
        int v=star[i].to;
        if(v==fa) continue;        
        if(du[u]==1){
            f[v]=g[v]+star[i].w;
        }
        else{
            f[v]=g[v]+min(f[u]-min(star[i].w,g[v]),star[i].w);
        }
        dfs(v,u);
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--){
        memset(head,0,sizeof(head));
        cnt=0;
        memset(g,0,sizeof(g));
        memset(f,0,sizeof(f));
        memset(du,0,sizeof(du));
        int n;
        cin>>n;
        for(int i=1;i<=n-1;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            du[u]++;
            du[v]++;
            add(u,v,w);
            add(v,u,w);
        }
        dp(1,0);
        f[1]=g[1];
        dfs(1,0);
        int ans=0;
        for(int i=1;i<=n;i++) ans=max(ans,f[i]);
        cout<<ans<<endl;
    }
}
原文地址:https://www.cnblogs.com/kamimxr/p/11541606.html