一、适用的问题描述:
某家族人口过于庞大,要判断两个是否是亲戚不容易。先给出已知的亲戚关系图,求任意给出的两人是否为亲戚关系。规定亲戚有传递性。
样例输入/输出:
6 5 3 (说明:6个人,5个亲戚关系,3组判断)
1 2
1 5
3 4
5 2
1 3
1 4 Yes
2 3 Yes
5 6 No
二、并查集图文解释:
三、下面的程序,和上图原理稍有不同。不是用最小元素标记,请读者仔细揣摩。
参考程序(C++版)
#define _CRT_SECURE_NO_DEPRECATE //一定要放最前面才可起作用
#include <stdio.h> //可用cstdio代替
#define MAX 5001 //元素个数
int P[MAX]; //标记数组
using namespace std; //命名空间
class MyClass{ //类声明
public:
MyClass(int N);//构造函数
void merge(int p, int q);//加入关系圈
bool isConnected(int p, int q);//判断是否在同一个圈中
int count();//计算有多少个圈
//int find(int p);
private:
int n;//数据成员
};
//如两值根的指向一致,则为同一圈
bool MyClass::isConnected(int p, int q)
{
if (P[p] == P[q]) return true;
else return false;
}
//
void MyClass::merge(int p, int q)
{
int p_id = P[p];
int q_id = P[q];
if (!this->isConnected(p,q)){ //通过之前关系判断亲缘
int i;
for (i = 1; i < this->n; i++){
if (P[i] == p_id) P[i] = q_id; //右值链到左值上,他们有同一根
}
}
}
MyClass::MyClass(int N){
this->n = N;
int i;
for (i = 1; i < N; ++i) P[i] = i;
}
int main(){
int n, m, p, i, Mi, Mj;
scanf("%d%d%d",&n,&m,&p);
MyClass mc(n);
for (i = 0; i < m; i++)
{
scanf("%d%d", &Mi,&Mj);
mc.merge(Mi,Mj);
}
for (i = 0; i < p; ++i)
{
scanf("%d%d",&Mi,&Mj);
if (mc.isConnected(Mi, Mj)) printf("Yes");
else printf("No");
}
}
运行结果:
欢迎继续交流,兰理工Q:316190672