hdu 4679 树状dp

本文介绍了一种使用树形DP算法解决特定问题的方法。通过两次深度优先搜索(DFS),算法能够找出切断任意一条边后的最大收益。首先进行一次DFS预处理,计算每个节点作为根时的最长路径;接着进行第二次DFS,遍历所有边并计算断开每条边后的最大收益。
摘要由CSDN通过智能技术生成

思路:我们其实只需要枚举每条边,求得最小值就行了。

先dfs算出每个节点作为根时,其子树的最长路径,以及进过该节点的最长,次长,第三长路径。

然后在次dfs枚举求出切断某条边,求出这条边的两个端点为子树根,其子树的最长路径。b就是其中较大的。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
#define Maxn 200010
using namespace std;
int road[Maxn],Max[Maxn],lMax[Maxn],vi[Maxn],e,head[Maxn],dis[Maxn],ldis[Maxn],pr,ans,sMax[Maxn],lroad[Maxn];
struct Edge{
    int u,v,val,id,next;
}edge[Maxn*4];
void init()
{
    memset(road,0,sizeof(road));
    memset(Max,0,sizeof(Max));
    memset(lMax,0,sizeof(lMax));
    memset(vi,0,sizeof(vi));
    memset(dis,0,sizeof(dis));
    memset(ldis,0,sizeof(ldis));
    memset(head,-1,sizeof(head));
    memset(sMax,0,sizeof(sMax));
    memset(lroad,0,sizeof(lroad));
    e=0;
}
void add(int u,int v,int val,int id)
{
    edge[e].u=u,edge[e].v=v,edge[e].val=val,edge[e].id=id,edge[e].next=head[u],head[u]=e++;
    edge[e].u=v,edge[e].v=u,edge[e].val=val,edge[e].id=id,edge[e].next=head[v],head[v]=e++;
}
void dfs(int u)
{
    int i,v;
    vi[u]=1;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].v;
        if(vi[v]) continue;
        dfs(v);
        if(Max[v]+1>Max[u])
        {
            sMax[u]=lMax[u];
            lroad[u]=road[u];
            lMax[u]=Max[u];
            Max[u]=Max[v]+1;
            road[u]=v;
        }
        else
        if(Max[v]+1>lMax[u])
        {
            sMax[u]=lMax[u];
            lMax[u]=Max[v]+1;
            lroad[u]=v;
        }
        dis[u]=max(dis[u],Max[u]+lMax[u]);
        dis[u]=max(dis[u],dis[v]);
    }
}
void predfs(int u,int d,int pre,int fa)
{
    int i,v;
    vi[u]=1;
    int now=0;
    int a,b=0;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].v;
        if(vi[v]) continue;
        a=edge[i].val;
        now=pre;
        if(road[u]==v)
        {
            now=max(d+lMax[u],now);
            now=max(lMax[u]+sMax[u],now);
            b=max(now,dis[v]);
            if(a*b<=pr)
            {
                if(a*b==pr)
                {
                    if(edge[i].id<ans)
                    ans=edge[i].id;
                }
                else
                pr=a*b,ans=edge[i].id;
            }
            predfs(v,max(d,lMax[u])+1,now,u);
        }
        else
        if(lroad[u]==v)
        {
            now=max(d+Max[u],now);
            now=max(Max[u]+sMax[u],now);
            b=max(now,dis[v]);
            if(a*b<=pr)
            {
                if(a*b==pr)
                {
                    if(edge[i].id<ans)
                    ans=edge[i].id;
                }
                else
                pr=a*b,ans=edge[i].id;
            }
            predfs(v,max(d,Max[u])+1,now,u);
        }
        else
        {
            now=max(d+Max[u],now);
            now=max(Max[u]+lMax[u],now);
            b=max(now,dis[v]);
            if(a*b<=pr)
            {
                if(a*b==pr)
                {
                    if(edge[i].id<ans)
                    ans=edge[i].id;
                }
                else
                pr=a*b,ans=edge[i].id;
            }
            predfs(v,max(d,Max[u])+1,now,u);
        }
    }
}
int main()
{
    int n,i,j,m,t,u,v,w,Case=0;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        for(i=1;i<=n-1;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w,i);
        }
        int a,b;
        dfs(1);
        memset(vi,0,sizeof(vi));
        pr=2000000000;
        ans=10000000;
        predfs(1,0,0,0);
        printf("Case #%d: %d\n",++Case,ans);
    }
    return 0;
}

 

 

转载于:https://www.cnblogs.com/wangfang20/p/3262308.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值