洛谷题单指南-二叉树-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;;
}