P1525 [NOIP 2010 提高组] 关押罪犯
P1525 [NOIP 2010 提高组] 关押罪犯
大意
给定若干对关系,让将这些人分入两个集合中,在同一集合中的两个有关系的人会贡献出来其边权,让求 \(\min(\max(s1, s2))\)。
思路
考虑二分图染色 + 二分。
很经典的话语:“最大值最小”,因此我们可以考虑二分答案,然后我们想想,二分完答案 \(k\) 之后怎么做?
显然对于哪些关系值小于等于 \(k\) 的我们是不是不需要考虑,只需要让关系值大于 \(k\) 的那些罪犯不在一个监狱中。
对于这个问题,差不多算 \(0 / 1\) 染色,只需要二分图染色,因为只有两个监狱,如果能染成功,就说明答案有可能小于等于 \(k\),否则说明答案大于 \(k\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 20010;
struct node {
int v, w;
};
vector<node> g[N];
int color[N], n, m;
bool dfs(int u, int k) {
bool ok = true;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i].v, w = g[u][i].w;
if(w <= k) continue;
if(color[v] == -1){
color[v] = 1 - color[u];
ok &= dfs(v, k);
}
else if(color[v] == color[u]){
ok &= false;
}
}
return ok;
}
bool check(int k) {
memset(color, -1, sizeof(color));
bool ok = true;
for (int i = 1; i <= n; i++) {
if (color[i] == -1) {
color[i] = 0;
ok &= dfs(i, k);
}
}
return ok;
}
int main() {
cin >> n >> m;
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
int l = 0, r = 1000000001;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
cout << r;
return 0;
}
本文来自一名高中生,作者:To_Carpe_Diem

浙公网安备 33010602011771号