P3884 [JLOI2009]二叉树问题

如下图所示的一棵二叉树的深度、宽度及结点间距离分别为:

深度:4 宽度:4(同一层最多结点个数)

结点间距离: ⑧→⑥为8 (3×2+2=8)

⑥→⑦为3 (1×2+1=3)

注:结点间距离的定义:由结点向根方向(上行方向)时的边数×2,

与由根向叶结点方向(下行方向)时的边数之和。

输入格式

输入文件第一行为一个整数n(1≤n≤100),表示二叉树结点个数。接下来的n-1行,表示从结点x到结点y(约定根结点为1),最后一行两个整数u、v,表示求从结点u到结点v的距离。

输出格式

三个数,每个数占一行,依次表示给定二叉树的深度、宽度及结点u到结点v间距离。

输入输出样例

  展开

题目描述

如下图所示的一棵二叉树的深度、宽度及结点间距离分别为:

深度:4 宽度:4(同一层最多结点个数)

结点间距离: ⑧→⑥为8 (3×2+2=8)

⑥→⑦为3 (1×2+1=3)

注:结点间距离的定义:由结点向根方向(上行方向)时的边数×2,

与由根向叶结点方向(下行方向)时的边数之和。

输入格式

输入文件第一行为一个整数n(1≤n≤100),表示二叉树结点个数。接下来的n-1行,表示从结点x到结点y(约定根结点为1),最后一行两个整数u、v,表示求从结点u到结点v的距离。

输出格式

三个数,每个数占一行,依次表示给定二叉树的深度、宽度及结点u到结点v间距离。

输入输出样例

输入 #1复制

10                                
1 2                            
1 3                            
2 4
2 5
3 6
3 7
5 8
5 9
6 10
8 6

输出 #1

4
4
8

思路记录:题目就是几个基础题叠加在一起,求树的深度,树的宽度,两节点的最近公共祖先

比较难一点的就是求树的公共祖先,看了很多题解才明白,被自己菜哭的一天,递归有时候确实很难理解

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include<bits/stdc++.h>
using namespace std;
int a[105][2];
int wid[105];
int maxdeep=0;
int ans[105];
int root1,root2,n;
void dfs(int deep,int root){
    wid[deep]++;//当前深度的宽度加一
    ans[root]=deep-1;//当前节点的深度
    if(a[root][0]==0&&a[root][1]==0){
        maxdeep=max(maxdeep,deep);//求最大深度
        return ;
    }
    if(a[root][0]) dfs(deep+1,a[root][0]);
    if(a[root][1]) dfs(deep+1,a[root][1]);
}
int lca(int root){ //找公共祖先,判断root节点又没有可能是公共祖先,这个算法等于复杂度O(n)
    //每一次递归就是需要判断该节点的左节点和右节点是否满足条件
    if( root == 0 || root == root1 || root == root2) return root;
    int left = lca(a[root][0]);
    int rigth = lca(a[root][1]);//根后序遍历相比差不多
    if(left == 0 && rigth == 0) return 0;//该节点两个节点都不包含root1,root2
    if(left == 0) return rigth;//右节点是,返回rigth给上一层
    if(rigth == 0) return left;//左节点是,返回left 给上一层
    return root;//左右节点都是,所以该节点就是公共祖先,直接返回
}
int main(){

    int s1,s2;

    cin>>n;
    for(int i=0;i<n-1;i++){
        cin>>s1>>s2;
        if(a[s1][0]==0)
            a[s1][0]=s2;
        else a[s1][1]=s2;
    }
    cin>>root1>>root2;
    dfs(1,1);
    cout<<maxdeep<<endl;
    int maxwid=0;
    for(int i=0;i<105;i++)
        maxwid=max(maxwid,wid[i]);
    cout<<maxwid<<endl;
    int lcaroot = lca(1);
    cout<<ans[root1]*2+ans[root2]-3*ans[lcaroot]<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值