题目:
题目链接:
https://vjudge.net/contest/369847#problem/A
考察点:
并查集的变种、并查集补集
并查集补集是个什么东东:
相信大家听到补集这个词语应该不会感到陌生,但是在这里并查集补集的概念有一丢丢不同。
这里通俗一点说就是一种相反的关系。比如 A 和 B 都有 10 元钱,现在 A 看上 B 了,决定
将自己的小金库交给 B 保管,那么现在 A 就剩 0 元,相应的 B 会增加 10 元。
这是一种相对的关系,放到并查集会对应什么呢?
拿这两个监狱来说,如果说 A 和 B 在同一个监狱,那么相反的肯定是 A 和 B 不在同一个监狱.
相对应的就是两个集合 -- 两种状态,of course 有多种状态的话肯定对应这多个集合。
你也许会有疑问,为什么这种补集的方法要开几倍的空间,开一倍空间是不够吗?
(菜鸡的我会有这种疑问,哈哈,大佬可以跳过了)
在这类并查集问题中,我们往往不仅要知道两者的显性的关系,还需要了解两者之间的隐式关系。
然而我们在并查集查找时为了便于快速查找,采用了压缩路径的方法,导致我们原先的一些关系
乱套了,比如 A、B、C 三个人搞三角恋,在同一个集合中了,你现在能清楚的知道谁 love 谁
吗?显然不够明了。
那么我们在合并时要怎样合并呢?
首先需要扩大一下数组,如果中有 x 种关系,就扩大 x 倍。
拿这道题来说:
我们需要开两倍: A: 1 2 3
B: 1 2 3
A 集合中的 1 对应 B 集合中 1 ,其他同理。
如果说我们知道 1 和 3 在同一个监狱,而且他们的危险最大,我们就需要讲两者分开。
所以 A 中的 1 和 B 中的 3 合并
A 中的 3 和 B 中的 1 合并
从而得出两者的相对关系。
侃侃:
相信你看过上面的解释后会有一种拨开云雾见日月的感觉,如果有,是我的荣幸,如果
没有让你足够清楚,可能是我能力有限,如果你有好的见解希望分享给我。
下面说说这道题:
首先,威胁最大的一定不能够在同一个监狱,如果可以的话就没我们的事了。
所以,我们将所有的关系之间产生的威胁 从大到小进行排序。
其次,就开始并查集了,如果两者可以出现在不同的集合,就将两个人分在不同的集合中,表示
将两个人分在了不同的监狱。
为了更好的解释这个关系,请看下图:
Code:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 10;
typedef long long LL;
struct node {
int u,v,w;
}person[maxn];
int fa[maxn << 1];
int n,m;
bool cmp(node a,node b) {
return a.w > b.w;
}
int get(int x) {
return x == fa[x] ? x : fa[x] = get(fa[x]);
}
void Union(int x,int y) {
int xx = get(x);
int yy = get(y);
if(xx == yy) return ;
fa[yy] = xx;
return ;
}
int main(void) {
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; i ++) {
scanf("%d%d%d",&person[i].u,&person[i].v,&person[i].w);
}
// 初始化
for(int i = 1; i <= (n << 1); i ++) {
fa[i] = i;
}
// 先分开打的火热的
sort(person + 1,person + 1 + m,cmp);
// 看是不是所有人都可以入洞房
bool vis = false;
for(int i = 1; i <= m; i ++) {
int x = get(person[i].u);
int y = get(person[i].v);
// 说明还不是情敌
if(x != y) {
Union(x,y + n);
Union(y,x + n);
} else {
// 是情敌,必须干掉一个
printf("%d
",person[i].w);
vis = true;
break;
}
}
if(!vis)
puts("0");
return 0;
}
后记:
通过这道题,也学到了不少东西。
(人只能一心一意爱一个人,哈哈)
对这种扩展域并查集有了更清楚的认知,当初看食物链那道题很懵,有了并查集
补集的这个概念,就很好理解了。
还有一种二分的解法,有空要学习一下。
前路漫漫,仍需努力。