最近公共祖先(并查集)

E - Nearest Common Ancestors

  POJ - 1330 
#include<stdio.h>
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
typedef long long LL;
int par[10010];//父亲
int ra[10010], rb[10010];
queue<int>road;

void init(int n) {
	for (int i = 0; i <= n; i++) {
		par[i]=i;
	}
}

int Find1(int x) { //不需要记录路径的查找
	if (par[x] == x)return x;
	else {
		return Find1(par[x]);
	}
}

int Find(int x) {  //需要记录路径的查找
	road.push(x);
	if (par[x] == x)return x;
	else {
		return Find(par[x]);
	}
}

void unite(int a, int b) {
	if (Find1(a) == Find1(b))return;
	par[b] = a; //不能按照并查集那样合并  find也不需要压缩路径
}

int main() {
	int Case;
	scanf_s("%d", &Case);
	while (Case--) {
		int n; scanf_s("%d", &n);
		init(n);
		for (int i = 0; i < n - 1; i++) {
			int a, b;
			scanf_s("%d%d", &a, &b);
			unite(a, b);
		}//建立并查集
		int a, b;
		scanf_s("%d%d", &a, &b);
		int ia = -1, ib = -1;
		while (!road.empty())road.pop();
		Find(a);
		while (!road.empty()) {
			ra[++ia] = road.front();
			road.pop();
		}//路程放入数组
		Find(b);
		while (!road.empty()) {
			rb[++ib] = road.front();
			road.pop();
		}//路程放入数组
		while (ia >= 0 && ib >= 0) {
			if (ra[ia] == rb[ib]) { ia--; ib--; }
			else { printf("%d\n", ra[ia + 1]); break; }
		}
		if (ia < 0)printf("%d\n", rb[ib + 1]);
		else if (ib < 0)printf("%d\n", ra[ia + 1]);
	}
}



主要运用并查集,查询时候记录查询的路径,并比较两个路径的区别,即可找到最近的公共祖先。

注意:查询写了两个函数,一个是记录路径一个是不记录路径,若只写一个记录路径提交的时候会 Memory Limit Exceeded

猜你喜欢

转载自blog.csdn.net/leo_10/article/details/80931334