洛谷题单指南-二叉树-P3884 [JLOI2009] 二叉树问题

原题链接:https://www.luogu.com.cn/problem/P3884

题意解读:要计算二叉树的深度、宽度、节点间的距离,深度、宽度的概念很好理解,节点间的距离描述是:节点 之间的距离表示从的最短有向路径上向根节点的边数的两倍加上向叶节点的边数。说人话就是:u到v的距离=uv最近公共祖先到u的距离 * 2 + uv最近公共祖先到v的距离。

解题思路:

对于深度来说,P4913已经做过介绍,DFS可以解决;

对于宽度来说,只需要在DFS计算深度的过程中,记录每一个深度一共有多少个节点,最后取某个深度最多的节点数量即是宽度;

对于距离来说,如x到y的距离,需要先求x、y的最近公共祖先f,然后计算x到f的距离* 2 + y到f的距离 即可。

求x、y的最近公共祖先,可以通过向上标记法,遍历x的所有祖先(包括x自己),用数组fathers[]标记,再遍历y的所有祖先,第一个在fathers中标记过的即最近公共祖先。

由于要搜索祖先,二叉树节点需要存储父、子节点。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 105;

struct node
{
    int father, left, right;
} tree[N];

int n, u, v, x, y;
int maxdepth; //树的深度
int depthcnt[N]; //每种深度的节点数
int depthall[N]; //每个节点的深度

bool fathers[N]; //x的所有祖先标记

void dfs(int root, int depth)
{
    if(root == 0) return;
    maxdepth = max(maxdepth, depth); //更新树的深度
    depthcnt[depth]++; //深度depth的节点数++
    depthall[root] = depth;
    
    dfs(tree[root].left, depth + 1);
    dfs(tree[root].right, depth + 1);
}

int lca(int x, int y)
{
    int ans; 
    int tmpx = x, tmpy = y;
    while(tmpx)
    {
        fathers[tmpx] = true;
        tmpx = tree[tmpx].father;
    }
    while(tmpy)
    {
        if(fathers[tmpy]) 
        {
            ans = tmpy;
            break;
        }
        tmpy = tree[tmpy].father;
    }
    return ans;
}

int main()
{
    cin >> n;
    for(int i = 1; i < n; i++)
    {
        cin >> u >> v;
        if(tree[u].left == 0) tree[u].left = v;
        else tree[u].right = v;
        tree[v].father = u;
    }
    cin >> x >> y;
    dfs(1, 1);

    int width = 0; //树的宽度是深度最多的节点数
    for(int i = 1; i <= n; i++) width = max(width, depthcnt[i]);

    int f = lca(x, y);
    //x到y的距离=xy最近公共祖先到x的距离 * 2 + xy最近公共祖先到y的距离
    int distance = (depthall[x] - depthall[f]) * 2 + depthall[y] - depthall[f];

    cout << maxdepth << '\n' << width << '\n' << distance << endl;;
}

 

posted @ 2024-03-18 14:53  五月江城  阅读(44)  评论(0编辑  收藏  举报