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.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示 ...
随机推荐
- C# 使用Epplus导出Excel [4]:合并指定行
C# 使用Epplus导出Excel [1]:导出固定列数据 C# 使用Epplus导出Excel [2]:导出动态列数据 C# 使用Epplus导出Excel [3]:合并列连续相同数据 C# 使用 ...
- 【哈希 二分】bzoj2084: [Poi2010]Antisymmetry
可以用manacher或者SA搞过去的:非常有趣的hash题 Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串.比如0000 ...
- python入门:BREAK 的用法 跳当前循环后,不再执行下面代码块
#!/urs/bin/env python # -*- coding:utf-8 -*- # BREAK 的作用 跳当前循环后,不再执行下面代码块 while True: ') break ') #w ...
- Vue 父子组件间的通信
前言 在 Vue 项目中父子组件的通信是非常常见的,最近做项目的时候发现对这方面的知识还不怎么熟练,在这边做一下笔记,系统学习一下吧. 1 父组件传值给子组件 1.1 传值写法 父组件传值给子组件,这 ...
- Decorator——Python初级函数装饰器
最近想整一整数据分析,在看一本关于数据分析的书中提到了(1)if __name__ == '__main__' (2)列表解析式 (3)装饰器. 先简单描述一下前两点,再详细解说Python初级的函数 ...
- 如何解决js跨域问题
Js跨域问题是web开发人员最常碰到的一个问题之一.所谓js跨域问题,是指在一个域下的页面中通过js访问另一个不同域下的数据对象,出于安全性考 虑,几乎所有浏览器都不允许这种跨域访问,这就导致在一些a ...
- loc与iloc函数的使用
Pandas中loc和iloc函数用法详解(源码+实例) https://blog.csdn.net/w_weiying/article/details/81411257 Pandas中loc,il ...
- 数学基础:HDU2802-F(N)(寻找循环节)
F(N) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissi ...
- MIP启发式算法:遗传算法 (Genetic algorithm)
*本文主要记录和分享学习到的知识,算不上原创 *参考文献见链接 本文主要讲述启发式算法中的遗传算法.遗传算法也是以local search为核心框架,但在表现形式上和hill climbing, ta ...
- debian7不能apt安装emacs24
维护者在主页上 http://emacs.naquadah.org/ 提到: These packages are not maintained anymore I don't use these p ...