题目链接

题目描述

S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

思路

法一:二分答案+二分图染色

如果这是一个二分图,那么就能达到完全不发生冲突事件的效果。

所以,我们可以考虑在原图上删去若干条边得到一个二分图。在这个二分图中,是没有冲突事件发生的。然后再加上刚刚删去的边,必然是在染成同一个颜色的点之间加边,因此所加的这些边就代表着会发生的冲突事件。

因此,就要使得删去的边的权值最小。而在之后所有加进去的边中只有权值最大的那条边有意义,因为是它决定了所有冲突事件中最大的影响力,权值比它小的边加进去也无关紧要。

因为具有单调性,可以先排序再二分答案删去的最大的一条边,将小于它的边全部删去然后\(check\).

法二:并查集

参考:http://hzwer.com/599.html

思路很巧妙。也是因为这个我才想明白了用并查集判断二分图是什么原理。

这道题最根本的想法其实就是要将怒气值最大的一对对犯人分开,而并查集是用来处理等价关系的,并且不等关系不具有传递性,怎么办呢?

那就将不等关系转化为等价关系。

将\(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 关押罪犯 二分答案+二分图染色 || 并查集的更多相关文章

  1. NOIP 2010 关押罪犯 并查集 二分+二分图染色

    题目描述: S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值" ...

  2. noip 2010 关押罪犯 (二分图染色 并茶几)

    /* 二分图染色版本 两个监狱对应二部图的两部分 在给定的怨气值里二分 对于每一个Ci 进行染色判断是否合法 染色的时候 如果这条边的ci > Ci 这两个人就带分开 即染成不同的颜色 如果染色 ...

  3. [NOIP 2010] 关押罪犯 (二分+二分图判定 || 并查集)

    题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"( ...

  4. NOIP 2010 关押罪犯

    P1525 关押罪犯 题目描述 SS 城现有两座监狱,一共关押着 NN 名罪犯,编号分别为 1-N1−N .他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突. ...

  5. noip提高组 2010 关押罪犯 (洛谷1525)

    题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"( ...

  6. BZOJ 3993: [SDOI2015]星际战争 [二分答案 二分图]

    3993: [SDOI2015]星际战争 题意:略 R1D2T1考了裸二分答案+二分图最大匹配... #include <iostream> #include <cstdio> ...

  7. HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流

    二分+最大流: 1 //题目大意:有编号为1~n的女生和1~n的男生配对 2 // 3 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架 4 // 5 //然后输入f组,c,d表示 ...

  8. HDU 3081 Marriage Match II (二分图,并查集)

    HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...

  9. NOIP提高组2010 关押罪犯

    题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示 ...

随机推荐

  1. Java面向对象基础 ——面试题

    1面向对象基础 JAVA基础语法自行掌握. 三大特性: 一 封装:★★★★★ 概念:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式. 好处:将变化隔离:便于使用:提高重用性:安全性. 封装原则: ...

  2. xmpp 协议详解

    XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测.它在促进服务器之间的准即时操作.这个协议可能最终允许因特网用户向因特网上的其他任何人发送 ...

  3. on() 和 click() 的区别

    on() 和 click() 的区别: 二者在绑定静态控件时没有区别,但是如果面对动态产生的控件,只有 on() 能成功的绑定到动态控件中. 以下实例中原先的 HTML 元素点击其身后的 Delete ...

  4. kmp和hash 字符串处理 哈希表

    来自http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 并进行自己的简单整 ...

  5. Fedora 28 系统基础配置以及常用软件安装方式

    实验说明: 很多人说Linux很难用,很难上手,其实不然,倘若不玩游戏,其实很多发行版Linux都可以成为主力系统,就比如本章要讲的 Fedora 28.本章会从镜像来源.系统安装.基础配置和常用软件 ...

  6. SpringMVC总结以及在面试中的一些问题.

    1.简单的谈一下SpringMVC的工作流程? 流程 1.用户发送请求至前端控制器DispatcherServlet 2.DispatcherServlet收到请求调用HandlerMapping处理 ...

  7. manjaro kde netease-cloud-music 网易云音乐

  8. poj 3050 地图5位数问题 dfs算法

    题意:一个5*5地图上面,从任意位置上下左右跳五次,组成一个数.问:不重复的数有多少个? 思路:dfs 从任意位置跳5次,说明每个位置都需要遍历. 组成一个数:number*10+map[dx][dy ...

  9. adb提取安装的apk

    第一步:列出所有安装的apk adb shell pm list packages  然后找到自己要取出来的apk的包名. 第二布:找到apk的位置(后面跟上包名) adb shell pm path ...

  10. socket编程了解

    Socket 编程 Socket通讯原理描述: 套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并进行连 ...