本文共 1407 字,大约阅读时间需要 4 分钟。
我们将罪犯当作点,罪犯之间的仇恨关系当作点与点之间的无向边,边的权重就是罪犯之间的仇恨值。这样,我们需要将所有点分成两组,使得各组内的边的权重的最大值最小。
我们可以在[0,1e9]之间二分枚举最大权值x。当x固定之后,我们就可以判断能否将所有点分成两组,使得权值大于x的边在两组之间,而小于等于x的权值在组内。也就是判断由所有点以及所有权值大于某一限的边构成的新图是否是二分图。
为了实现这一点,我们可以使用深度优先搜索(DFS)来进行图的染色。如果染色成功,就说明存在一个分割方式;否则,x需要增加。当检查到所有节点都被成功染色时,我们就找到了满足条件的最小最大权重值。
以下是实现代码:
#include#include #include #include #include #include using namespace std;const int N = 2e4 + 10, M = 2e5 + 10;int n, m;int h[N], e[M], ne[M], w[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 x) { color[u] = c; for (int i = h[u]; i != -1; i = ne[i]) { if (w[i] <= x) continue; int j = e[i]; if (!color[j]) { if (!dfs(j, 3 - c, x)) return false; } else if (color[j] == c) return false; } return true;}bool check(int x) { memset(color, 0, sizeof color); for (int i = 1; i <= n; i++) { if (color[i] == 0) { if (!dfs(i, 1, x)) return false; } } return true;}int main() { memset(h, -1, sizeof h); 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; while (l < r) { int mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } cout << l << endl; return 0;}
通过上述方法,我们可以高效地找到将图分成两个子图,使得每个子图中的最大边权重尽可能小的问题的最优解。这不仅解决了原有的问题,还通过二分枚举和深度优先搜索结合的方式,确保了算法的高效性和代码的可读性。
转载地址:http://ejgrz.baihongyu.com/