LUOGU 1525 关押罪犯 - 并查集拆点(对立点) / 二分+二分图染色
分析:
并查集:
第一步先将所有矛盾从大至小排序,显然先将矛盾值大的分成两部分会更优。
普通的并查集都只能快速合并两个元素至同一集合,却不能将两个元素分至不同集合。
对于将很多数分成两个集合,并给出两数存在的矛盾关系(A和B不能在一集合),普通并查集无法解决。
考虑见每个元素拆成两个点,拆出来的点是它的对立点(i+n),如果要把A和B分至不同集合,就连边 A->B+n,B->A+n(假设先不压缩路径),也就是说:将A与B的对立点分至一个集合 \(\Leftrightarrow\) 将A与B分至不同集合。当然这种思路只能解决分成两部分的情况。
二分+二分图染色
其实就是要求把有矛盾的分到不同组里,于是可以使用二分图染色。先排序,然后二分不能满足的第一个位置,将前面的矛盾关系进行二分图染色,如果然不成功(相邻节点颜色相同),那么更新答案。注意二分图染色要对每个未染色的点都染一次,因为建出来的图可能不联通。
code
并查集:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 50, M = 1e5 + 50;
int n, m, anc[N * 2];
struct node{
	int x, y, w;
	inline bool operator < (const node &b) const{
		return w > b.w;
	}
}edge[M];
inline int getAnc(int x){return x == anc[x] ? x : (anc[x] = getAnc(anc[x]));}
int main(){
	freopen("h.in", "r", stdin);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= 2 * n; i++) anc[i] = i;
	for(int i = 1; i <= m; i++)scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].w);
	sort(edge + 1, edge + m + 1);
	for(int i = 1; i <= m; i++){
		int fx = getAnc(edge[i].x), fy = getAnc(edge[i].y);
		if(fx == fy){
			printf("%d\n", edge[i].w);
			return 0;
		}
		else{
			anc[fx] = getAnc(edge[i].y + n);
			anc[fy] = getAnc(edge[i].x + n);
		}
	}
	printf("0");
	return 0;
}
二分+二分图染色:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 40, M = 1e5 + 50;
int n, m, col[N];
vector<int> G[N];
struct State {
	int u, c, f;
	State() {}
	State(int _u, int _c, int _f):u(_u), c(_c), f(_f) {}
};
queue<State> que;
struct node {
	int a, b, c;
	inline bool operator < (const node &g) const {
		return c > g.c;
	}
} item[M];
inline bool BiCheck(int mid) {
	memset(col, -1, sizeof(int) * (n + 5));
	while(!que.empty()) que.pop();
	for(int i = 1; i <= n; i++) G[i].clear();
	for(int i = 1; i <= mid; i++) {
		G[item[i].a].push_back(item[i].b);
		G[item[i].b].push_back(item[i].a);
	}
	for(int i = 1; i <= n; i++){
		if(col[i] == -1){
			col[i] = 0;
			que.push(State(i, 0, 0));
			while(!que.empty()) {
				State t = que.front();
				que.pop();
				int u = t.u, c = t.c, f = t.f;
				for(int e = G[u].size() - 1; e >= 0; e--) {
					int v = G[u][e];
					if(v == f) continue;
					if(col[v] != -1) {
						if(col[v] == c) return false;
						else continue;
					} else col[v] = c ^ 1, que.push(State(v, c ^ 1, u));
				}
			}
		}
	}
	return true;
}
int main() {
	freopen("h.in", "r", stdin);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i++) scanf("%d%d%d", &item[i].a, &item[i].b, &item[i].c);
	sort(item + 1, item + m + 1);
	int l = 1, r = m, ans = 0;
	while(l <= r) {
		int mid = l + r >> 1;
		if(!BiCheck(mid)) ans = item[mid].c, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d", ans);
	return 0;
}
												
											LUOGU 1525 关押罪犯 - 并查集拆点(对立点) / 二分+二分图染色的更多相关文章
- NOIP 2010 关押罪犯 并查集  二分+二分图染色
		
题目描述: S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值" ...
 - Luogu P1525 [NOIp2010提高组]关押罪犯 | 并查集
		
题目链接 这一道题,我用了并查集来做.在此题中,并查集的作用就是:将同一个监狱里的罪犯合并到一起. 思路:将每对罪犯之间的怨气值从大到小排序,再依次把他们分到不同的两个监狱里,当发现这一对罪犯已经在同 ...
 - NOIP2010关押罪犯[并查集|二分答案+二分图染色 | 种类并查集]
		
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示 ...
 - 洛谷P1525关押罪犯——并查集
		
题目:https://www.luogu.org/problemnew/show/P1525 并查集+贪心,从大到小排序,将二人分在不同房间,找到第一个不满足的即为答案. 代码如下: #include ...
 - [noip2010]关押罪犯 并查集
		
第一次看的时候想到了并查集,但是不知道怎么实现: 标解,f[i]表示i所属的集合,用f[i+n]表示i所属集合的补集,实现的很巧妙,可以当成一个使用并查集的巧妙应用: #include<iost ...
 - NOIP2010提高组] CODEVS 1069 关押罪犯(并查集)
		
这道这么简单的题目还写了这么久.. 将每个会发生冲突的两人的怒气进行排序,然后从怒气大到小,将两个人放到不同监狱中.假如两人都已经被放置且在同一监狱,这就是答案. ------------------ ...
 - P1525 关押罪犯  并查集
		
题目描述 SS城现有两座监狱,一共关押着NN名罪犯,编号分别为1-N1−N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值) ...
 - luogu1525 [NOIp2011]关押罪犯 (并查集)
		
先从大到小排序,看到哪个的时候安排不开了 给每个人拆成两个,如果x和y有矛盾,就给x和y‘.y和x’连边:如果a和b(或a'和b')在同一个集合里,说明他们一定要在同一个监狱里. #include&l ...
 - 关押罪犯 - 并查集&优先队列
		
题目地址:http://www.51cpc.com/web/problem.php?id=4261 Summarize: 此题最巧妙的是“敌人的敌人就是朋友!”,故需先将敌对关系放入优先队列,按怨恨值 ...
 
随机推荐
- C#调用第三方ocx控件  (winform /aspx)
			
C#调用第三方ocx控件 1..net环境在工具箱上点右键,选择自定义工具箱,然后选择你需要的COM或者OCX控件就可以了. 2.在自定义工具箱中加入相应的控件,设置id,在客户端脚本中直接引用它 ...
 - STL之vector容器的实现框架
			
说明:本文仅供学习交流,转载请标明出处,欢迎转载. 实现vector容器的思路等同于实现一个动态数组,以下我们參照源代码的相关资料,给出一个vector容器的大致框架,仅仅有声明,没给出详细的实现. ...
 - Android EditText回车不换行
			
有时候我们需要在EditText组件输入完直接点回车进入 回车点击事件中处理相关业务,总是换行很伤脑筋,索性网上搜了一个办法,很实用,在这里记下来. 首先获取组件id: edt_city= (Edit ...
 - 多类 SVM 的损失函数及其梯度计算
			
CS231n Convolutional Neural Networks for Visual Recognition -- optimization 1. 多类 SVM 的损失函数(Multicla ...
 - fatfs的设置
			
官方网址:file:///E:/%E5%8D%95%E7%89%87%E6%9C%BA/FATFS/ff13a/documents/doc/config.html 关于多个文件同时打开的配置::在ff ...
 - ftp 下载时防止从缓存中获取文件
			
//http://baike.baidu.com/link?url=QucJiA_Fg_-rJI9D4G4Z4687HG4CfhtmBUd5TlXrcWCeIEXCZxIh0TD7ng1wROAzAu ...
 - TableView相关属性
			
//是否要显示分隔线 tableView.separatorStyle = UITableViewCellSeparatorStyleNone; tableView.separatorStyle = ...
 - 怎样自己构建一个小型的Zoomeye----从技术细节探讨到实现
			
 转载请注明出处:viewmode=list">http://blog.csdn.net/u011721501?viewmode=list 0.概述 Zoomeye是个网络空间的搜 ...
 - 常用MVC框架
			
J2EE开常用的SSH或SSI框架,对应解决表示层.业务逻辑层.持久化层的问题,其中对表示层的解决方案最多,常见的有Struts1/2,Spring MVC等,实际上都是在最底层的Servlet规范中 ...
 - int to str
			
string int2str( int num){ if (num == 0 ) return " 0 " ; string str = "" ; int nu ...