Accumulation Degree 【POJ - 3585】

本文介绍了一种使用两次深度优先搜索(DFS)解决特定图论问题的方法,旨在找到从任意点到所有叶子节点路径上的最大权值总和。通过两遍DFS分别预处理子树最大流量和根节点出发的最大流量,最终确定全局最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题目大意

找出一个点,从这个点出发到所有叶子节点可以流经的权值最大,输出这个最大的权值

解题思路

这个题就是跑两遍dfs
第一遍dfs的时候我们处理出以这个节点为根所有的子树中,最大的流量我们用zi[x]来表示。那么zi[] 的转移状态可以这样写

 if(du[v]==1)
      zi[u]+=e[i].w;
 else
      zi[u]+=min(zi[v],e[i].w);

第二遍dfs的时候,处理出以x节点为根出发的最大流量,我们用g[x]表示

            if(du[u]==1)
                g[v]=zi[v]+e[i].w;
            else
                g[v]=zi[v]+min(g[u]-min(e[i].w,zi[v]),e[i].w);

然后找出最大值即可

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
    int v,nex,w;
};
node e[600005];
int f[200005],tot,du[200005],zi[200005],g[200005],vis[200005];
void init()
{
    tot=0;
    memset(f,-1,sizeof(f));
    memset(du,0,sizeof(du));
    memset(zi,0,sizeof(zi));
    memset(g,0,sizeof(g));
}
void add(int u,int v,int w)
{
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nex=f[u];
    f[u]=tot++;
}
void dfs1(int u)
{
    vis[u]=1;
    for(int i=f[u];i!=-1;i=e[i].nex)
    {
        int v=e[i].v;
        if(!vis[v])
        {
            dfs1(v);
            if(du[v]==1)
                zi[u]+=e[i].w;
            else
                zi[u]+=min(zi[v],e[i].w);
        }
    }
}
void dfs2(int u,int fa)
{
    vis[u]=1;
    //printf("%d\n",u);
    for(int i=f[u];i!=-1;i=e[i].nex)
    {
        int v=e[i].v;
        if(!vis[v])
        {
            if(du[u]==1)
                g[v]=zi[v]+e[i].w;
            else
                g[v]=zi[v]+min(g[u]-min(e[i].w,zi[v]),e[i].w);
            dfs2(v,u);
        }
    }
}
int main()
{
    int T,n,x,y,z;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d %d %d",&x,&y,&z);
            du[x]++;
            du[y]++;
            add(x,y,z);
            add(y,x,z);
        }
        memset(vis,0,sizeof(vis));
        dfs1(1);
        memset(vis,0,sizeof(vis));
        g[1]=zi[1];
        dfs2(1,-1);
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,g[i]);
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值