首页 > 其他分享 >P1525 [NOIP2010 提高组] 关押罪犯

P1525 [NOIP2010 提高组] 关押罪犯

时间:2023-10-19 19:44:55浏览次数:30  
标签:P1525 cnt return 关押 int NOIP2010 mid color find

P1525 [NOIP2010 提高组] 关押罪犯
法一:二分图

把犯人分配到两个监狱,使得监狱内的怒气值最大最小
分配到两个集合中,考虑二分染色
分析因为答案具有单调性所以可以二分:
判断x是否符合,只需要重建大于x的边,如果不能把它们分到两个集合中(二分染色失败),就往上调(考虑无限大,那么就不矛盾
当然也可无需重建,只需要跳过即可

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m;
struct node {
	int u, v, s;
}a[N];
int cnt,h[N], ne[2 * N], to[2 * N], w[2 * N];
void add(int a, int b, int c) {
	ne[++cnt] = h[a];
	to[cnt] = b;
	w[cnt] = c;
	h[a] = cnt;
}
int color[N];
bool dfs(int x,int c,int k) {
	color[x] = c;
	for (int i = h[x]; i; i = ne[i]) {
		if (w[i] < k) continue;//跳过
		if (!color[to[i]]) {
			if (dfs(to[i], 3 - c, k)) return 1;
		}
		else if (color[to[i]] == c) return 1;
	}
	return 0;
}
bool check(int x) {//模板
	for (int i = 1; i <= n; i++) {
		if (!color[i]) {
			if (dfs(i,1,x)) return false;
		}
	}
	return true;
}
int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int a, b, c;
		cin >> a >> b >> c;
		add(a, b, c);
		add(b, a, c);
	}
	int l = 0, r = 1e9 + 10;
	while (l + 1 < r) {
		memset(color, 0, sizeof color);//清零
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid;
	}
	cout << l;
	return 0;
}

法二:种类并查集
如果你出错可能是因为排序的长度写成了n不要问我怎么知道的
1.要想怒气值小,必定是要把怒气值大的两人分开,因此要从大到小排序(事无绝对
2.把两人分开,注意:敌人的敌人是朋友,因为它没地方可去
3.如果两人在同一集合,那么直输出:如果把两人分开,必定会造成更大的怒气值,因为排过序

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m;
struct node {
	int u, v, s;
}a[N];
int f[N * 2];
int find(int x) {
	return f[x] == x ? x : f[x] = find(f[x]);
}
void unit(int x, int y) {
	int fx = find(x), fy = find(y);
	f[fx] = fy;
}
int main() {
	cin >> n >> m;
	for (int i = 1; i <= 2 * n; i++) f[i] = i;
	for (int i = 1; i <= m; i++) {
		cin >> a[i].u >> a[i].v >> a[i].s;
	}
	sort(a + 1, a + 1 + m, [](node x, node y) {//排序为m
		return x.s > y.s;
		});
	for (int i = 1; i <= m; i++) {
		int x=a[i].v, y = a[i].u;
		if (find(x)==find(y)) {
			cout << a[i].s;
			break;
		}
		else {
			unit(x, y + n);
			unit(y,x + n);
		}
		if (i == m) cout << 0;
	}
	return 0;
}

标签:P1525,cnt,return,关押,int,NOIP2010,mid,color,find
From: https://www.cnblogs.com/bu-fan/p/17775199.html

相关文章

  • [NOIP2010 提高组] 乌龟棋
    题目背景小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。题目描述乌龟棋的棋盘是一行NN个格子,每个格子上一个分数(非负整数)。棋盘第11格是唯一的起点,第NN格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。乌龟棋中MM张爬行卡片,分成44种不同的类型(MM张......
  • P1540 [NOIP2010 提高组] 机器翻译
    传送门题目背景小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。题目描述这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果内存中有,软件就会用它进行翻译;......
  • P1514 [NOIP2010 提高组] 引水入城
    link搜索。首先先用\(dfs\)判断一下对于每一个点来说对应的可以覆盖的\(L,R\).假设题目一定存在一个解,所以一定会有该点覆盖的区间连续。设该区间为\(L,R\),若不是每一个点均会被覆盖,那么题目不会存在任何一个解。判断是否有解:跑一遍\(dfs\),记录每一个点被\(dfs......
  • 「NOIP2010」机器翻译 题解
    前言附加任务这道题也是一个简单模拟题。传送门解析这道题就是一个简单的模拟题,简单来说就是如果内存里面没有这个单词(其实是一个数)的话就从外存入队,如果内存容量不够,出队即可。对了,每次查询时还要计数噢!代码话不多说上代码#include<bits/stdc++.h>usingnamespacestd......
  • [NOIP2010 提高组] 乌龟棋
    题目大意有四种卡片,它们分别可以让你前进1格,2格,3格和4格.在前进的道路上到达每个格子都会得到对应的积分.现在分别给出四种卡片的数量,求用完所有卡片能获得的最大积分和思路由于卡片只有4种,且每种的数量不超过20张,所以想到开四维dp,用dp[i][j][k][z]来表示用掉i张卡片4,j......
  • 算法学习记录:[NOIP2010]机器翻译
    题目链接https://ac.nowcoder.com/acm/contest/20960/1003记录:这道题我真的吃......
  • 23.4.15 NOIP2010提高游记
    第一次做提高,之前做的都是普及,还是感觉挺难的,心态有点裂开。1.机器翻译这题首先一看就是一道模拟题目,要注意的是字典的内存问题,在超内存以后要减1,直接上代码:-),时间复杂度O(n)1#include<bits/stdc++.h>2#pragmaGCCopzimize(3)3usingnamespacestd;4inlinelon......
  • P1540 [NOIP2010 提高组] 机器翻译
    P1540[NOIP2010提高组]机器翻译[NOIP2010提高组]机器翻译题目背景小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。题目描述这个翻译软件的......
  • 【NOIP2010】【codevs1069】关押罪犯(二分答案+二分图染色)
    problem将n个罪犯分别关押进2座监狱每2个罪犯之间有一个冲突值,当他们在同一监狱时就会爆发让爆发的冲突值(最大的那个)最小,求那个最小值solution考虑判定:是否存在一种分配方案......
  • 【NOIP2010】【Vijos1775】乌龟棋
    problemsolutioncodes#include<iostream>usingnamespacestd;intn,m,a[355],b[5],dp[40][40][40][40];intmain(){cin>>n>>m;for(inti=0;i<......