并查集(小雷的冰茶几、排座位)

并查集的理解

并查集主要是用来合并集合或者判断是否有相同的祖先的关系,可以将不同的元素合并到同一个集合中,想要查询的时候可以直接查询。

例题——小雷的冰茶几(并查集)

小雷的冰茶几
Description

小雷有个特殊的癖好,平时喜欢收藏各种稀奇古怪的东西,譬如。。。。,还有。。。。,也包括。。。。。小雷是一个喜欢分享的童鞋,这次小雷又给大家带来一套神奇的东西,那就是举世无双的冰茶几!
顾名思义,这些茶几被冰冻住了,最主要的是他们是易碎品,毕竟被冻住了。因此小雷要很小心翼翼的移动他们。一些茶几是冻在一起的,因此一套冰茶几分为好几部分,并且如果茶几A与B冻在一起,B与C冻在一起,那么A与C也就冻在了,即冰冻状态有传递性,ABC此时会看作一个整体。
为了保证冰茶几的完整性,小雷每次只能移动一整块冰茶几,也就是冰冻在一起的一部分。小雷想知道他需要搬几次才能全部搬到实验室,你能帮小雷快速计算出答案么?

Input

多组输入,先输入组数T(1 < = T < = 200)。
对于每组输入,先输入一个整数n(1 < = n < = 100000),k(0 < = k < = 100000),茶几编号1~n。
之后k行,每行两数x,y(1 < = x,y < = n),表示第x个茶几和第y个茶几冰冻在一起。

Output

对于每组输入,先输出”Case z: ”(不带引号)表示组数,再输出一个整数,表示小雷需要搬动的次数。
Sample
Input

3

3 1

1 2

5 2

1 2

3 4

5 2

1 2

2 3

Output

Case 1: 2

Case 2: 3

Case 3: 3

AC代码

#include <bits/stdc++.h>
using namespace std;
int f[100010];//该数组存放关系
int find(int x)//关键函数,找关系
{
    
    
	if (x == f[x])
		return x;
	else
		return find(f[x]);
}
int main()
{
    
    
	int t;
	cin >> t;
	int cas = 0;
	while (t--)
	{
    
    
		int  n, k;
		cin >> n >> k;
		for (int i = 1; i <= n; i++)
		{
    
    
			f[i] = i;
		}
		for (int i = 0; i < k; i++)
		{
    
    
			int x, y;
			cin >> x >> y;
			int fx = find(x);
			int fy = find(y);
			f[fx] = fy;
			//以上三步为寻找有相同关系的并相连
			//也可简化成一步f[find(x)]=find(y);
		}
		int sum = 0;
		for (int i = 1; i <= n; i++)
		{
    
    
			if (f[i] == i)sum++;
		}
		cout << "Case " << ++cas << ": " << sum << endl;
	}
	return 0;
}

例题——排座位

7-10 排座位 (25分)
布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。

输入格式:
输入第一行给出3个正整数:N(≤100),即前来参宴的宾客总人数,则这些人从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系,其中关系为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号。

这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。

输出格式:
对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but…;如果他们之间只有敌对关系,则输出No way。

输入样例:
7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2
输出样例:
No problem
OK
OK but…
No way

AC代码

#include<bits/stdc++.h>
#include <vector>
using namespace std;
int f[110];//并查集存放朋友关系
vector<int> G[110];//二维数组存放敌对关系
int find(int x)
{
    
    
	return f[x] == x ? x : find(f[x]);
}
int main()
{
    
    
	int n, k, m;
	cin >> n >> m >>k;
	for (int i = 1; i <= n; i++)
	{
    
    
		f[i] = i;
	}
	for (int i = 1; i <= m; i++)
	{
    
    
		int x, y, r;
		cin >> x >> y >> r;
		if (r == 1)
		{
    
    
			int fx = find(x);
			int fy = find(y);
			f[fx] = fy;
		}
		else
		{
    
    
			G[x].push_back(y);
			G[y].push_back(x);
		}
	}
	for (int i = 1; i <= k; i++)
	{
    
    
		int x, y;
		cin >> x >> y;
		int fx = find(x);
		int fy = find(y);
		if (fx == fy)
		{
    
    
			int flag = 1;
			for (int j = 0; j < G[x].size(); j++)
			{
    
    
				if(G[x][j]==y)
				{
    
    
					flag = 0; break;
				}
			}
			if (flag)
				cout << "No problem\n";
			else
				cout << "OK but...\n";
		}
		else
		{
    
    
				int flag = 1;
				for (int j = 0; j < G[x].size(); j++)
				{
    
    
					if (G[x][j] == y)
					{
    
    
						flag = 0; break;
					}
				}
				if (flag)
					cout << "OK\n";
				else
					cout << "No way\n";
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/rookie636/article/details/107971990