HDU--2196---Computer(树形DP)

这道题还是比较不容易理解的

主要是多用了一个dfs,多饶了一个弯

这道题符合树形DP的特征,可以把问题转化为一棵树


对于每一个点,计算出以此点为根的子树中的第一长的枝和第二长枝,都存起来

这是一个相当重要的预处理


当图转为树的时候,对于每一个点其最远点有两种情况(两种情况取最优)

1.返回父节点,来寻找最远点

2.直接继续向下找,找到最远点

对于第二种情况,由于向下找,长度必定为其最长枝的长度,预处理中已经找到,只需要在最后比较一下就OK

主要就是看前两种情况:

对于第二种情况,需要找一下可以向上走的最大长度,由于第二次求最远点的dfs中可以从根节点开始计算,向下依次递推

但是需要分情况1.该点在这棵树的最长枝中  2.该点未在这棵树的最长枝中

具体详解在代码中体现

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 11111
struct Edge
{
    int v,w,next;
} edge[MAXN<<1];
int NE,head[MAXN];
void addEdge(int u,int v,int w)
{
    edge[NE].v=v;
    edge[NE].w=w;
    edge[NE].next=head[u];
    head[u]=NE++;
}
long long d[3][MAXN];
int idx[MAXN];
void dfs0(int u,int fa)//fa表示u的父节点
{
    long long mx0=0,mx1=0;//mx0存最大的,mx1存第二大的
    for(int i=head[u]; i!=-1; i=edge[i].next)//搜索所有的边
    {
        int v=edge[i].v;
        if(v==fa) continue;
        dfs0(v,u);//递归求值
        if(mx0<=d[0][v]+edge[i].w) mx1=mx0,mx0=d[0][v]+edge[i].w,idx[u]=v;//idx记录最长路径
        else if(mx1<d[0][v]+edge[i].w) mx1=d[0][v]+edge[i].w;
        else if(mx1<d[1][v]+edge[i].w) mx1=d[1][v]+edge[i].w;
    }
    d[0][u]=mx0;//d[0][u]表示以u为跟的树两条最长枝,mx0,mx1
    d[1][u]=mx1;//
}
void dfs1(int u,int fa)
{
    for(int i=head[u]; i!=-1; i=edge[i].next)//搜索所有的边
    {
        int v=edge[i].v;
        if(v==fa) continue;
        if(idx[u]==v) d[2][v]=max(d[1][u]+edge[i].w,d[2][u]+edge[i].w);//如果在最长路径中
        else d[2][v]=max(d[0][u]+edge[i].w,d[2][u]+edge[i].w);//
        dfs1(v,u);
    }
}
int main()
{
    int n,a,b;
    while(~scanf("%d",&n))
    {
        NE=0;
        memset(head,-1,sizeof(head));
        for(int i=2; i<=n; ++i)
        {
            scanf("%d%d",&a,&b);
            addEdge(i,a,b);
            addEdge(a,i,b);
        }
        memset(d,0,sizeof(d));
        dfs0(1,1);
        dfs1(1,1);
        for(int i=1; i<=n; ++i)
        {
            printf("%lld\n",max(d[0][i],d[2][i]));
        }
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值