HDU 2196——Computer(树形DP)

膜拜了NN个大神的代码,看了一整天,弱菜伤不起啊。求拜师啊


问题分析求树上每个节点到其它节点的最远距离

每个节点到其它节点的最远距离就是以该节点为根的树所能达到的最大深度,这样子的话,要把每个节点转化为根,总共dfs的次数为节点数,肯定超时

于是~

一个节点的最长路:1.从该节点往下取得最长路(子树部分)  2.从该节点往上取得的最长路(父节点往上的部分)

情况1自下而上的dfs(先深搜后操作)

情况2自上而下的dfs(先操作后深搜){

如果节点u的子节点v在 以u为父亲的子树上的最长路,那么点v的最长路由u的父亲路次长路中的max取得

否则 点v的最长路由u的父亲路最长路中的max取得

}

(画颗树就可以非常清楚了)


贴上自己的代码~~~   

^。^


<span style="font-size:18px;">/*dp[i][0] 表示以i为父亲的子树中的最大距离
dp[i][1] 表示以i为父亲的子树中的次大距离
dp[i][2] 表示i的父树的最大距离
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ms(s,i) memset(s,i,sizeof s)
#define ffl(i,r) for(int i=head[r];i!=-1;i=edge[i].next)
#define lng long long
#define pb push_back
#define linf 100000
#define M 11000
#define fx(i,x,n) for(int i=x;i<n;++i)
using namespace std;
int dp[M][3],f[M],l[M],vis[M];
template<class T> T gcd(T a,T b){return b==0?a:gcd(b,a%b);}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
struct pp{int v,w,next;}edge[M*2];int tot,head[M],root,n,m;
inline void addedge(int u,int v,int w,int *h){edge[tot].v=v,edge[tot].w=w,edge[tot].next=h[u],h[u]=tot++;}//邻接表

void dfs1(int u)//自下而上,更新子树的最长路和次长路,先dfs后操作
{
    vis[u]=1;
    ffl(i,u){//引用邻接表
        int v=edge[i].v;//节点u的子节点
        if(vis[v]) continue;
        dfs1(v);
        if(dp[u][0]<dp[v][0]+edge[i].w){//最长的是所有子节点中的max
            dp[u][1]=dp[u][0];
            dp[u][0]=dp[v][0]+edge[i].w;
        }
        else if(dp[u][1]<dp[v][0]+edge[i].w){//次长的是所有子节点的second
            dp[u][1]=dp[v][0]+edge[i].w;
        }
    }
}
void dfs2(int u)
{
    vis[u]=1;
    ffl(i,u){//引用邻接表
        int v=edge[i].v;//节点u的子节点
        if(vis[v]) continue;
        if(dp[v][0]+edge[i].w==dp[u][0]){//节点v的最长路+边(u,v)的权值=节点u的最长路,那么节点v在节点u的最长路上
            dp[v][2]=max(dp[u][1],dp[u][2])+edge[i].w;//等于父亲路和次长路中的MAX
        }
        else
            dp[v][2]=max(dp[u][2],dp[u][0])+edge[i].w;//否则等于父亲路和最长路中的MAX
        dfs2(v);//自上而下
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF){
        int u,w;
        tot=0,ms(head,-1);//记得初始化
        for(int i=2;i<=n;++i){
            scanf("%d%d",&u,&w);
            addedge(u,i,w,head);addedge(i,u,w,head);//邻接表构建无向图
        }
        ms(vis,0),ms(dp,0);
        dfs1(1);
        ms(vis,0);//重新初始化vis
        dfs2(1);
        for(int i=1;i<=n;++i){
            printf("%d\n",max(dp[i][0],dp[i][2]));//最长路和父亲路中的MAX
        }
    }
    return 0;
}
</span>



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值