257. 关押罪犯

算法

二分图+判定

思路

显然要让答案最小,应让怨气值较大的不在同一监狱。尽量让较小的在同一个监狱里矛盾。及分成两个集合。满足二分图。而后二分答案,以最后的怨气值为mid,凡大于mid的罪犯都需在不同集合,只需判定是否为二分图即可。

核心

二分图判定+染色法

bool dfs(int x, int color) {
	v[x] = color;
	for (unsigned int i = 0; i < e[x].size(); i++) {
		int y = e[x][i].first;
		if (v[y]) {
			if (v[y] == color) return 0;
		} else {
			if (!dfs(y, 3 - color)) return 0;
		}
	}
	return 1;
}

  

 二分

while (l < r) {
		int mid = (l + r) >> 1;
		if (pd(mid)) r = mid;
		else l = mid + 1;
	}

代码

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 20006, M = 200006;
struct P {
	int x, y, z;
	bool operator < (const P w) const {
		return z > w.z;
	}
} p[M];
int n, m, v[N];
vector<pair<int, int> > e[N];

bool dfs(int x, int color) {
	v[x] = color;
	for (unsigned int i = 0; i < e[x].size(); i++) {
		int y = e[x][i].first;
		if (v[y]) {
			if (v[y] == color) return 0;
		} else {
			if (!dfs(y, 3 - color)) return 0;
		}
	}
	return 1;
}

inline bool pd(int now) {
	for (int i = 1; i <= n; i++) e[i].clear();
	for (int i = 1; i <= m; i++) {
		if (p[i].z <= now) break;
		e[p[i].x].push_back(make_pair(p[i].y, p[i].z));
		e[p[i].y].push_back(make_pair(p[i].x, p[i].z));
	}
	memset(v, 0, sizeof(v));
	for (int i = 1; i <= n; i++)
		if (!v[i] && !dfs(i, 1)) return 0;
	return 1;
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++)
		scanf("%d %d %d", &p[i].x, &p[i].y, &p[i].z);
	sort(p + 1, p + m + 1);
	int l = 0, r = p[1].z;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (pd(mid)) r = mid;
		else l = mid + 1;
	}
	cout << l << endl;
	return 0;
}

  

原文地址:https://www.cnblogs.com/ruanmowen/p/12724163.html