AcWing 3555. 二叉树

AcWing 3555. 二叉树_第1张图片

第一种做法是dfs。但是注意,如果是非常单纯的dfs,要把每个节点可以到达的所有节点都记录下来(父节点+两个子节点)。如果只记录了子节点,没记录父节点,就失去了一个方向,肯定出错。

例如求2和6之间的路径:因为这是一棵树,所以从a到b的路径只有唯一的一条。

AcWing 3555. 二叉树_第2张图片

void dfs(int cur, int b, int depth){
	if(cur == b){
		ans = depth;
		return ;
	}
	for(int i = 0; i < 3; i++){
		int x = v[cur][i];
		if(x != -1 && !vis[x]) {
			vis[x] = 1;
			dfs(x, b, depth + 1); 
		}
	}
	return ;
}
int main(){
	scanf("%d", &t);
	while(t--){
		int n, m;
		scanf("%d%d", &n, &m);
		memset(v, -1, sizeof(v));
		for(int i = 1; i <= n; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			v[i][0] = a; 
			v[i][1] = b; 
			if(a != -1) v[a][2] = i;
			if(b != -1) v[b][2] = i;
		}
		ans = 0;
		memset(vis, false, sizeof(vis));
		for(int i = 1; i <= m; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			vis[a] = 1;
			dfs(a, b, 0);
			printf("%d\n", ans);
		}
	} 
	return 0;

 但是dfs明显有点麻烦,那么我们使用LCA。

2.LCA:最近公共祖先。在二叉树中找到两个节点的最近的公共根节点。

这题求a和b之间的距离,那么我们在建树的时候就已经算出了每个节点到根节点之间的距离。然后我们来看看根据这个距离数组怎么计算两个节点之间的路径。

AcWing 3555. 二叉树_第3张图片

 这么画个图是不是就知道怎么通过各个节点到根节点的距离计算任意两点之间的路径了!

那么我们怎么计算各个点到根节点的距离呢?很简单,从它的父节点传递过来一个depth,那么当前节点到根节点的距离一定是父节点的深度+1.

那么我们怎么计算两个点的最近公共祖先呢?很简单,一直去找父亲,直到他们的父亲是同一个人。

好了。现在上代码(这个代码除了输出,看样子就是最简单的lca模板了,积累一下):

#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int N = 1010;
const int M = 1010;
int l[N];
int r[N];
int dep[N];
int p[N];
int n, m, t; 
void dfs(int root){  //找根节点到各个节点的距离
    if(root == -1) return ;
    if(l[root] > 0) dep[l[root]] = dep[root] + 1;
    if(r[root] > 0) dep[r[root]] = dep[root] + 1;
    
    dfs(l[root]);
    dfs(r[root]);
}
int main(){
	scanf("%d", &t);
	while(t--){
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			l[i] = a;
			r[i] = b;
			if(a != -1) p[a] = i;
			if(b != -1) p[b] = i;
		}
		dfs(1);
		for(int i = 1; i <= m; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			int x = a;
			int y = b;
			while(a != b){
			    if(dep[a] > dep[b]){
			        a = p[a];
			    }else{
			        b = p[b];
			    }
			}   
			
			printf("%d\n", dep[x] + dep[y] - 2 * dep[a]);
		}
	} 
	
	return 0;
} 

还有用链表的形式查找两个节点的最近公共祖先,代码如下:

TreeNode* lowestCommonAncestor(TreeNode* root,TreeNode* p,TreeNode* q){
    //已经到叶子节点了,找到p或者找到q了,因为值是唯一的,所以在另一半的子树上要么没有,要么剩下其他的
    if(root==NULL||root==p||root==q) return root;   
    TreeNode* left=lowestCommonAncestor(root->left,p,q);  //递归到左子树
    TreeNode* right=lowestCommonAncestor(root->right,p,q);  //递归到右子树
    if(left==NULL&&right==NULL) return NULL;  //都不在树中
    else if(left!=NULL&&right!=NULL) return root;  //左右子树各有一个,那么说明公共祖先是根节点
    else return left==NULL?right:left;
}

就到这吧,我的脑子真的很不好使,但是我应该给我自己一点积极的暗示!

我有一个好脑子!

我有一个好脑子!

我有一个好脑子!

你可能感兴趣的:(蓝桥杯,深度优先,算法,图论)