并查集的理解
例题——小雷的冰茶几(并查集)
小雷的冰茶几
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;
}