给定N名罪犯和M组仇恨关系,第i组关系用a[i],b[i],w[i]标识,表示编号为a[i]与b[i]的罪犯之间的仇恨值为w[i]。现要将所有罪犯关押在两个房间里,使得同一房间内任意两名罪犯的最大仇恨值最小,求该最小值。
提示1:排查+种类并查集。类似最小生成树的做法,按仇恨值从大到小排序,按顺序枚举每个关系,如果双方已经在一起,则无法解决,当前仇恨值即为答案,否则将两人分开放。
#include <bits/stdc++.h>
using i64 = long long;
struct Edge {
int x, y, w;
};
struct DSU {
std::vector<int> f;
DSU(int n) {
init(n);
}
void init(int n) {
f.resize(n);
std::iota(f.begin(), f.end(), 0);
}
int find(int x) {
while (x != f[x]) {
x = f[x] = f[f[x]];
}
return x;
}
void join(int x, int y) {
x = find(x);
y = find(y);
if (x != y) {
f[y] = x;
}
}
bool same(int x, int y) {
return find(x) == find(y);
}
};
void solve() {
int N, M;
std::cin >> N >> M;
std::vector<Edge> edge(M);
for (int i = 0; i < M; i++) {
std::cin >> edge[i].x >> edge[i].y >> edge[i].w;
edge[i].x--;
edge[i].y--;
}
std::sort(edge.begin(), edge.end(), [&](auto &u, auto &v){
return u.w > v.w;
});
DSU dsu(2*N);
for (auto &e : edge) {
if (dsu.same(e.x, e.y)) {
std::cout << e.w << "\n";
return;
}
dsu.join(e.x, e.y+N);
dsu.join(e.x+N, e.y);
}
std::cout << 0 << "\n";
}
int main() {
std::cin.tie(0)->sync_with_stdio(0);
int t = 1;
while (t--) solve();
return 0;
}
提示2:二分+二分图。二分答案,假设当前答案为mid,将仇恨值大于mid的关系连边形成图,如果该图是二分图,则mid可行,否则不可行。
#include <bits/stdc++.h>
using i64 = long long;
struct Edge {
int x, y, w;
};
bool isbp(int n, const std::vector<std::vector<int>> &adj) {
std::vector<int> vis(n);
auto dfs = [&](auto self, int x, int c) -> bool {
vis[x] = c;
for (auto i : adj[x]) {
if (vis[i] == c) {
return false;
}
if (vis[i] == 0 && !self(self, i, -c)) {
return false;
}
}
return true;
};
for (int i = 0; i < n; i++) {
if (vis[i]) {
continue;
}
if (dfs(dfs, i, 1) == 0) {
return false;
}
}
return true;
}
void solve() {
int N, M;
std::cin >> N >> M;
std::vector<Edge> edge(M);
for (int i = 0; i < M; i++) {
std::cin >> edge[i].x >> edge[i].y >> edge[i].w;
edge[i].x--;
edge[i].y--;
}
std::sort(edge.begin(), edge.end(), [&](auto &u, auto &v){
return u.w > v.w;
});
auto check = [&](int val) {
std::vector<std::vector<int>> adj(N);
for (auto &e : edge) {
if (e.w <= val) {
break;
}
adj[e.x].push_back(e.y);
adj[e.y].push_back(e.x);
}
return isbp(N, adj);
};
int lo = 0, hi = 1e9, mid;
while (lo < hi) {
mid = (lo + hi) / 2;
if (check(mid)) {
hi = mid;
} else {
lo = mid + 1;
}
}
std::cout << lo << "\n";
}
int main() {
std::cin.tie(0)->sync_with_stdio(0);
int t = 1;
while (t--) solve();
return 0;
}
标签:std,return,关押,int,auto,edge,--,罪犯,lgP1525
From: https://www.cnblogs.com/chenfy27/p/18257519