最近公共祖先
Description
前面我们学习过了树这种特殊的数据结构。我们知道除了根结点,树上的每个都有父结点。这里我们提到另外一个概念,祖先 结点。所谓祖先结点,就是父结点的父结点,父结点的父结点的父结点…,所有沿着父亲结点向根结点走的结点都能称为祖先结点。特殊的是,自己也可以称为自己的祖先结点。
两个结点的最近公共祖先结点就是这两个结点沿着父节结点一直到根结点的路径上第一个相遇的结点。给出一棵树,求出树上的两个结点的最近公共祖先。
Input
输入第一行一个整数 n(1 ≤ n ≤ 1000) 表示树的结点数,结点的编号为 1 到 n。
接下来一行,输入 n 个用空格隔开的整数,第 i 个整数表示结点 i 的父亲节点。如果是 -1 表示该结点为根节点。
接下来一行输入两个整数 u, v(1 ≤ u, v ≤ n)。
Output
输出结点 u 和 v 的最近公共祖先结点的编号。
Sample Input 1
5
-1 1 2 2 1
5 4
Sample Output 1
1
Sample Input 2
7
4 6 1 7 2 7 -1
6 5
Sample Output 2
6
——摘自YCOJ
这道题提到了一个祖先节点,并且自己也可以称为自己的祖先结点,我们可以把它画成一棵树:
本题要用到一个重要的概念,set集合。
set的构造:
C++ 中直接构造一个 set 的语句为: set s 。这样就定义了一个名为 s 的、储存 T 类型数据的集
合,其中 T 是集合要储存的数据类型。初始的时候 s 是空集合。比如 set a ,set b
等等。
插入元素:
C++ 中用 insert() 方法向set中插入一个新的元素。注意如果set中已经存在了某个元素,再次插
入不会产生任何效果,set中是不会出现重复元素的(自动去重)。
查找元素:
C++ 中如果我们要想知道某个元素是否在set中出现,你可以直接用 count() 方法。如果set中存在我们
要查找的元素,返回 true ,否则会返回 false 。
以上是本题需要用到关于set的操作,但不够全面,在我们机房大佬herobrineAC那里,有关于集合的总体概述以及函数实现。
https://blog.csdn.net/qq_44635637/article/details/87207454
回归正题,这道题用set在合适不过了,我们开一个fa数组,利用循环向set里插入i元素,在对它进行查找,找出最近公共祖先结点的编号,就可以完成本题了。
#include<bits/stdc++.h>
using namespace std;
int fa[1010];
set<int> st;
int main(){
int n;
cin >> n;
for(int i=1;i <= n;i++){
cin >> fa[i];
}
int u,v;
cin >> u >> v;
for(int i = u;i != -1;i = fa[i]){
st.insert(i);
}
for(int i = v;i != -1;i = fa[i]){
if(st.count(i)){
cout << i;
return 0;
}
}
return 0;
}