解法一:二分 + 二分图匹配
时间复杂度:$O((m + n) \times log(c))$
二分的为满足 $> w[i]$ 的所有边权即仇恨值能够构成一个二分图的最大值,而判断 $> w[i]$ 的所有边权能否构成二分图可参考 AcWing 860. 染色法判定二分图 的讲解。
C++ 代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 20010, M = 200010;
int n, m;
int h[N], w[M], e[M], ne[M], idx;
int color[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int u, int c, int mid)
{
color[u] = c;
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (w[i] <= mid) continue; // i == idx
if (!color[j]) {
if (!dfs(j, 3 - c, mid)) return false;
}
else if (color[j] == c) return false;
}
return true;
}
bool check(int mid)
{
memset(color, 0, sizeof(color));
for (int i = 1; i <= n; ++i) {
if (!color[i]) {
if (!dfs(i, 1, mid)) {
return false;
}
}
}
return true;
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof(h));
while (m--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
int l = 0, r = 1e9;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << r << endl;
return 0;
}
解法二:并查集 + 扩展域 + 贪心
时间复杂度:$O(m \times log(m))$
先将所有边权从大到小排序,$p[i]$ 表示 $i$ 所在的监狱,$p[i + n]$ 表示 $i$ 的敌人所在的监狱,而不可避免事件为敌人的敌人仍为敌人时,直接输出即可。
C++ 代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 40010, M = 100010;
int n, m;
int p[N];
struct Node {
int a, b, c;
}e[M];
bool cmp(Node x, Node y)
{
return x.c > y.c;
}
int find(int x)
{
if (p[x] != x) return find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; ++i) cin >> e[i].a >> e[i].b >> e[i].c;
sort(e + 1, e + 1 + m, cmp);
for (int i = 1; i <= n << 1; ++i) {
p[i] = i;
}
for (int i = 1; i <= m; ++i) {
int x = find(e[i].a);
int y = find(e[i].b);
if (x == y) {
cout << e[i].c << endl;
return 0;
}
p[y] = find(e[i].a + n);
p[x] = find(e[i].b + n); // 扩展域
}
cout << 0 << endl;
return 0;
}