目前我所用到的并查集的题目主要是在判断是否有环存在与最小联通图上面,下面来看一下例题吧。
判断是否有环存在
众所周知,XP学长即将毕业了,所以他觉得在校园里来一次漫步,在学校中有N个标志性的建筑,XP学长并不喜欢走小路,因此他会随机的选择某条大路从某个建筑走到另一个建筑,XP学长当然想要走遍校园内的所有建筑,但他会随机的选择某一条路去漫步,当然XP学长走完某一条路,绝对不会走这一条路,也就是说,如果XP学长当前所在建筑为v,他选择走v->u的某一条大路e,到达u建筑后,他在之后的漫步里不会再选择这条路,但是这仍然可能导致他到达某个建筑两次,XP学长表示他不想观看同样的建筑两次,因此他想问问你,如果他随机的选择这些路去漫步,是否会出现到达一个建筑两次或两次以上的现象,当然了,XP学长可以选择任意的建筑作为他的起始点。
输入
输入包含多组测试用例,第一行输入一个T表示测试数据组数,(1<=T<=10),每组测试数据首先输入有两个整数N,M,N表示校园内有N个建筑(分别用1-N来标记它们),M表示校园内有M条大路,它们连接着这些建筑。(2<=N<=10^5,1<=M<=10^5),接下来M行每行两个整数u,v,表示u,v之间有一条大路(1<=u,v<=N),每条大路都是无向的,保证图中不出现自环现象,不保证图是连通的。
输出
如果XP学长随机漫步,会出现上述现象,请输出YES,否则输出NO。
样例输入 Copy
1 4 3 1 2 2 3 1 3
样例输出 Copy
YES
提示
在样例中,XP学长可以选择1作为他的起始建筑,那么他可能走这样的一条路径:1->2->3->1,此时XP学长到达了建筑1两次,因此你需要输出YES。
代码如下
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
int par[100005];
int get(int a){
if (par[a] != a) {
par[a] = get(par[a]); //不断找父节点
}
return par[a];
}
int merge(int u, int v) {
int get_u = get(u);
int get_v = get(v);
if (get_u == get_v) {
return 0;
}
par[get_v] = u;//加入集合
return 1;
}
int main() {
int t;
while (cin >> t) {
int n, m;
while (t--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
par[i] = i;//赋值,本身就是父节点
}
int flag = 0;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
if(merge(u,v)==0)
{
flag = 1;//如果flag等于1则表示存在环
}
}
if (flag == 1)cout << "YES" << endl;
if (flag == 0)cout << "NO" << endl;
}
}
return 0;
}
接下来是最小连通图问题:
X星大学新校区终于建成啦!
新校区一共有N栋教学楼和办公楼。现在需要用光纤把这N栋连接起来,保证任意两栋楼之间都有一条有线网络通讯链路。
已知任意两栋楼之间的直线距离(单位:千米)。为了降低成本,要求两栋楼之间都用直线光纤连接。
光纤的单位成本C已知(单位:X星币/千米),请问最少需要多少X星币才能保证任意两栋楼之间都有光纤直接或者间接相连?
注意:如果1号楼和2号楼相连,2号楼和3号楼相连,则1号楼和3号楼间接相连。
输入
单组输入。
第1行输入两个正整数N和C,分别表示楼栋的数量和光纤的单位成本(单位:X星币/千米),N<=100,C<=100。两者之间用英文空格隔开。
接下来N*(N-1)/2行,每行包含三个正整数,第1个正整数和第2个正整数表示楼栋的编号(从1开始一直到N),编号小的在前,编号大的在后,第3个正整数为两栋楼之间的直线距离(单位:千米)。
输出
输出最少需要多少X星币才能保证任意两栋楼之间都有光纤直接或者间接相连。
样例输入 Copy
3 10 1 2 5 1 3 6 2 3 7
样例输出 Copy
110
代码如下:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
struct node {
int a;
int b;
int c;
}e[105];
int cmp(node x, node y) {
return x.b < y.b;
}
int f[105];
int get(int k) {
return f[k] == k ? k : get(f[k]);
}
int main() {
int n, c;
cin >> n>> c;
int sum = 0;
for (int i = 1; i <= n * (n - 1) / 2; i++) {
cin >> e[i].a >> e[i].b >> e[i].c ;
}
sort(e+1, e + (n * (n - 1) / 2)+1, cmp);
for (int i = 1; i <= n * (n - 1) / 2; i++)
f[i] = i;
for (int i = 1; i <= n * (n - 1) / 2; i++) {
int x = get(e[i].a);
int y = get(e[i].b);
if (x != y) {
f[y] = x;
sum = sum + e[i].c;
}
else continue;
}
cout << sum * c << endl;
}