noip 2010 关押罪犯 二分答案+二分图染色 || 并查集
题目链接
题目描述
S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。
那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?
思路
法一:二分答案+二分图染色
如果这是一个二分图,那么就能达到完全不发生冲突事件的效果。
所以,我们可以考虑在原图上删去若干条边得到一个二分图。在这个二分图中,是没有冲突事件发生的。然后再加上刚刚删去的边,必然是在染成同一个颜色的点之间加边,因此所加的这些边就代表着会发生的冲突事件。
因此,就要使得删去的边的权值最小。而在之后所有加进去的边中只有权值最大的那条边有意义,因为是它决定了所有冲突事件中最大的影响力,权值比它小的边加进去也无关紧要。
因为具有单调性,可以先排序再二分答案删去的最大的一条边,将小于它的边全部删去然后\(check\).
法二:并查集
思路很巧妙。也是因为这个我才想明白了用并查集判断二分图是什么原理。
这道题最根本的想法其实就是要将怒气值最大的一对对犯人分开,而并查集是用来处理等价关系的,并且不等关系不具有传递性,怎么办呢?
那就将不等关系转化为等价关系。
将\(i+n\)看作\(i(1\leq i\leq n)\)的敌人。那么在分开\(u,v\)时,说明\(u\)是\(v\)的敌人,因此\(u\)和\(v+n\)是一类,\(v\)和\(u+n\)是一类,于是可以将它们分别合并。如果哪次发现要分开的两个点已经在同一个集合中,就说明这两个点已经分不开了。因为是从大往小合并,当前这条边的权值就是会发生的冲突的最大值。
比较
从具体实现可见,法一要做\(logn\)次并查集,而法二只要做一次并查集。
因为出发点是不同的,法一是从二分图染色出发,而法二本身就是并查集的思路。可见二分图和并查集关系紧密,以后要多想想是否能够进行转化。
Code
Ver. 1
#include <bits/stdc++.h>
#define maxn 40010
#define maxm 100010
using namespace std;
typedef long long LL;
int fa[maxn], sz[maxn];
struct node {
int u, v, val;
bool operator < (const node& nd) const {
return val < nd.val;
}
}a[maxm];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
void unionn(int x, int y) {
x = find(x), y = find(y);
if (x == y) return;
if (sz[x] > sz[y]) swap(x, y);
fa[x] = y, sz[y] += sz[x];
}
int n, m;
bool check(int id) {
for (int i = 1; i <= (n<<1); ++i) sz[i] = 1, fa[i] = i;
for (int i = id+1; i < m; ++i) {
if (find(a[i].u) == find(a[i].v)) return false;
unionn(a[i].u, a[i].v+n);
unionn(a[i].v, a[i].u+n);
}
return true;
}
int main() {
freopen("prison.in", "r", stdin);
freopen("prison.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 0; i < m; ++i) scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].val);
sort(a, a+m);
int l = -1, r = m-1;
while (r > l) {
int mid = l+r>>1;
if (check(mid)) r = mid;
else l = mid+1;
}
if (~l) printf("%d\n", a[l].val);
else printf("0\n");
return 0;
}
Ver.2
#include <bits/stdc++.h>
#define maxn 40010
#define maxm 100010
using namespace std;
typedef long long LL;
int fa[maxn], sz[maxn];
struct node {
int u, v, val;
bool operator < (const node& nd) const {
return val > nd.val;
}
}a[maxm];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
void unionn(int x, int y) {
x = find(x), y = find(y);
if (x == y) return;
if (sz[x] > sz[y]) swap(x, y);
fa[x] = y, sz[y] += sz[x];
}
int n, m;
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; ++i) scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].val);
sort(a, a+m);
for (int i = 1; i <= (n<<1); ++i) sz[i] = 1, fa[i] = i;
for (int i = 0; i < m; ++i) {
if (find(a[i].u) == find(a[i].v)) { printf("%d\n", a[i].val); exit(0); }
unionn(a[i].u, a[i].v+n);
unionn(a[i].v, a[i].u+n);
}
printf("0\n");
return 0;
}
noip 2010 关押罪犯 二分答案+二分图染色 || 并查集的更多相关文章
- NOIP 2010 关押罪犯 并查集 二分+二分图染色
题目描述: S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值" ...
- noip 2010 关押罪犯 (二分图染色 并茶几)
/* 二分图染色版本 两个监狱对应二部图的两部分 在给定的怨气值里二分 对于每一个Ci 进行染色判断是否合法 染色的时候 如果这条边的ci > Ci 这两个人就带分开 即染成不同的颜色 如果染色 ...
- [NOIP 2010] 关押罪犯 (二分+二分图判定 || 并查集)
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"( ...
- NOIP 2010 关押罪犯
P1525 关押罪犯 题目描述 SS 城现有两座监狱,一共关押着 NN 名罪犯,编号分别为 1-N1−N .他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突. ...
- noip提高组 2010 关押罪犯 (洛谷1525)
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"( ...
- BZOJ 3993: [SDOI2015]星际战争 [二分答案 二分图]
3993: [SDOI2015]星际战争 题意:略 R1D2T1考了裸二分答案+二分图最大匹配... #include <iostream> #include <cstdio> ...
- HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流
二分+最大流: 1 //题目大意:有编号为1~n的女生和1~n的男生配对 2 // 3 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架 4 // 5 //然后输入f组,c,d表示 ...
- HDU 3081 Marriage Match II (二分图,并查集)
HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...
- NOIP提高组2010 关押罪犯
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示 ...
随机推荐
- 什么是静态代码块?java中如何使用空参构造方法自动生成不同名字的对象,使用非静态的属性和静态属性有什么区别,原因是什么?如何理解static关键字
静态代码块?类加载就执行,最先执行 class demo{ static int num; static{ num=10; num*=3; System.out.println("haha& ...
- 如何在 JavaScript 中更好地使用数组
使用 Array.includes 替代 Array.indexOf “如果需要在数组中查找某个元素,请使用 Array.indexOf.” 我记得在我学习 JavaScript 的课程中有类似的这么 ...
- NOIP模拟赛 双色球
[题目描述] 机房来了新一届的学弟学妹,邪恶的chenzeyu97发现一位学弟与他同名,于是他当起了善良的学长233 “来来来,学弟,我考你道水题检验一下你的水平……” 一个栈内初始有n个红色和蓝色的 ...
- 【MySql】Mysql ERROR 1067: Invalid default value for ‘date’ 解决
在给一个表添加字段的时候,忽然发现会报一个date类型的字段的默认值错误,郁闷~ 经过排查,原来是MySQL的配置问题,在wamp下,MySQL 5.7里是没有设置 SQL_MODE 的. 1.my. ...
- iPhone如何设置自定义铃声?无需连接电脑,轻松几步就搞定!
转载自: https://baijiahao.baidu.com/s?id=1594988016778457969&wfr=spider&for=pc 受够了iPhone自带的千篇一律 ...
- python有三元运算符吗
所属网站分类: python基础 > 语法,变量,运算符 作者:goodbody 链接: http://www.pythonheidong.com/blog/article/12/ 来源:pyt ...
- LeetCode (160) Intersection of Two Linked Lists
题目 Write a program to find the node at which the intersection of two singly linked lists begins. For ...
- C++中重载、覆盖和隐藏的区别,以及适用场景
一.重载.覆盖和隐藏的区别 二.适用场景 1.重载: 适用于不同的数据类型都需要使用到的功能函数.以数据相加的函数为例,可以在同一个文件内提供以下的重载函数以支持同样的功能: int add(int, ...
- Linux学习-Tarball 的管理与建议
使用原始码管理软件所需要的基础软件 从原始码的说明我们晓得要制作一个 binary program 需要很多咚咚的呢!这包括底下这些基础的软件: gcc 或 cc 等 C 语言编译程序 (compil ...
- 《鸟哥的Linux私房菜》学习笔记(3)——根文件系统
一.Linux目录结构 rootfs:根文件系统,根是"/". 1./boot 系统启动相关的文件,如内核.intrd.以及grub(bootloader) root@hao:~# ...