HDU 2196 Computer(树形dp+换根法+树的直径)

题意:给出一棵树,求离每个节点最远的点的距离

分析:

方法一:贪心做法,不会证明,找到直径的两个端点,分别dfs一下,求出两端到每个点分别的距离取最大值,树的直径作用很大啊。

方法二:把无根树转化成有根树分析,对于每个节点,维护所有以当前节点为根的子树中距当前节点最远的距离和次远距离,二次扫描(两遍dfs)。

参考:https://blog.csdn.net/shuangde800/article/details/9732825http://www.mamicode.com/info-detail-1114779.html

代码一(方法一):

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
vector<int> G[N],L[N];
int n,a,b,dis1[N],dis2[N],len,fa,fb;

void dfs(int pre, int v, int d[], int x){
    d[v] = x;
    for (int i = 0; i < G[v].size(); ++i){
        int u = G[v][i];
        if (u == pre) continue;
        dfs(v, u, d, x + L[v][i]);
    }
    if (x > len){
        len = x;
        fa = v;
    }
}

int main(){
    while (~scanf("%d",&n)){
        for (int i = 0; i <= n; ++i){
            G[i].clear();
            L[i].clear();
        }
        for (int i = 2; i <= n; ++i){
            scanf("%d%d",&a,&b);
            G[a].push_back(i);
            G[i].push_back(a);
            L[a].push_back(b);
            L[i].push_back(b);
        }
        len = -1;
        dfs(-1, 1, dis1, 0);
        len = -1;
        dfs(-1, fa, dis1, 0);
        len = -1;
        dfs(-1, fa, dis2, 0);
        for (int i = 1; i <= n; ++i)
            printf("%d\n",max(dis1[i], dis2[i]));
    }
    return 0;
}

代码二(方法二):

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
struct Edge{
    int ne,to,dis;
}edge[N];

int h[N],cnt=0;
void add_edge(int f,int to,int c){
    edge[++cnt].ne=h[f];
    edge[cnt].to=to;
    edge[cnt].dis=c;
    h[f]=cnt;
}

int n,m;
int f[N],g[N],t[N];
/// f--最大值 g--次大值,都是向下走到的最远距离
void dfs(int u,int fa){
    int v,x;
    int p=0,pp=0;///p--max pp--smaller than max
    for(int i=h[u];i;i=edge[i].ne){
        v=edge[i].to;
        if(v==fa)continue;
        dfs(v,u);
        x=f[v]+edge[i].dis;
        if(p<x) pp=p,p=x,t[u]=v;
        else if(pp<x) pp=x;///这一句话千万不要忘了加
    }
    f[u]=p,g[u]=pp;
    return ;
}

int q[N];   ///向上走到的最远距离
void dfs2(int u,int fa){
    int v,x;
    for(int i=h[u];i;i=edge[i].ne){
        v=edge[i].to;
        if(v==fa)continue;
        if(v==t[u])x=g[u];
        else x=f[u];
        q[v]=max(q[u],x)+edge[i].dis;
        dfs2(v,u);
    }
    return ;
}

int main(){
	int x,y,z;
    while(scanf("%d",&n)!=EOF){
        memset(h,0,sizeof(h));
        for(int i=2;i<=n;i++){
            scanf("%d%d",&x,&y);
            add_edge(i,x,y);
            add_edge(x,i,y);
        }
        f[1]=g[1]=0;
        dfs(1,0);
        q[1]=0;
        dfs2(1,0);
        for(int i=1;i<=n;i++)
            printf("%d\n",max(f[i],q[i]));
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值