P3884 [JLOI2009]二叉树问题 洛谷-java-最近公共祖先

该博客详细解析了洛谷P3884题目的解题思路,包括如何利用最近公共祖先(LCA)算法求解二叉树的深度、宽度以及两个节点间的距离。通过深度优先搜索(DFS)遍历二叉树,存储每个节点的深度,并利用辅助数组计算宽度。同时,介绍了计算两点间距离的方法,即两个节点到最近公共祖先距离之和的两倍。

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

传送门:P3884 [JLOI2009]二叉树问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=M85Bhttps://www.luogu.com.cn/problem/P3884

 题目求三个数字:二叉树深度、宽度和x,y之间的距离。

一. 深度

使用lca求最近公共祖先的时候(对lca不熟的可以看这篇文章http://t.csdn.cn/XZ1xl),会用到数组(这里姑且叫做dis数组)dis来记录每一个结点的深度,那么深度遍历一遍数组,就能得到最大深度了。

//求depth
int depth = 0;
int[] wi = new int[maxn];
for(int i=1;i<=n;i++) {
    depth = Math.max(depth, dis[i]);
    wi[dis[i]]++;
}

二. 宽度

可以注意到上面代码中有一行是wi[dis[i]]++;,没错,这个就是用来求宽度的,我们把每一个深度的结点的数量记录在数组里面,然后for循环遍历一遍就ok了,结合下面代码:

//求宽度
int width = 0;
for(int i=1;i<=n;i++)
    width = Math.max(width, wi[i]);

三. 两结点之间的距离

根据题目的意思,两点之间距离 = 节点u到最近公共祖先的距离 * 2 + 节点v到最近公共祖先的距离,那么思路很明显了,lca后直接求解就行了。

int distance = (dis[x]-dis[father]) * 2 + (dis[y]-dis[father]);

完整代码:

import java.io.*;
import java.util.*;

public class Main {
    static int maxn=101;
    static int n, cnt;
    static int[] vv = new int[maxn<<1], to = new int[maxn<<1];
    static int[] he = new int[maxn];
    static int[] fa = new int[maxn],dis = new int[maxn];
    public static void main(String[] args) throws IOException {
        n = nextInt();
        for(int i=1;i<n;i++){
            int u = nextInt();
            int v = nextInt();
            addEdge(u,v);
            addEdge(v,u);
        }
        dfs(1,0);
        //求depth
        int depth = 0;
        int[] wi = new int[maxn];
        for(int i=1;i<=n;i++) {
            depth = Math.max(depth, dis[i]);
            wi[dis[i]]++;
        }
        //求宽度
        int width = 0;
        for(int i=1;i<=n;i++)
            width = Math.max(width, wi[i]);
        //求距离
        int x = nextInt();
        int y = nextInt();
        int father = lca(x,y);
        int distance = (dis[x]-dis[father]) * 2 + (dis[y]-dis[father]);
        out.println(depth);
        out.println(width);
        out.println(distance);
        out.close();
    }

    public static void dfs(int u,int father){
        fa[u] = father;
        dis[u] = dis[father] + 1;
        for(int i=he[u];i>0;i=to[i]) {
            if(vv[i] == father) continue;
            dfs(vv[i], u);
        }
    }

    public static int lca(int x,int y){
        while(x != y) {
            if (dis[x] >= dis[y])
                x = fa[x];
            else
                y = fa[y];
        }
        return x;
    }

    public static void addEdge(int u,int v){
        vv[++cnt] = v;
        to[cnt] = he[u];
        he[u] = cnt;
    }

    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

    public static int nextInt() throws IOException{
        in.nextToken();
        return (int)in.nval;
    }

    public static String nextString() throws IOException {
        in.nextToken();
        return in.sval;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玛卡左家陇分卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值