博客
关于我
算法竞赛进阶指南 关押罪犯
阅读量:714 次
发布时间:2019-03-21

本文共 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/

你可能感兴趣的文章
Remove Extra one 维护前缀最大最小值
查看>>
Linux操作系统的安装与使用
查看>>
C++ 继承 详解
查看>>
OSPF多区域
查看>>
Docker入门之-镜像(二)
查看>>
去了解拉绳位移编码器的影响因素
查看>>
无法初始化Winsock2.2处理
查看>>
vMotion 操作失败进度卡在14% ,报错: Operation Timed out
查看>>
重置UAG Application admin密码
查看>>
Horizon Daas租户管理平台扩展分配时报:内部错误
查看>>
嵌入式系统试题库(CSU)
查看>>
【自考】之信息资源管理(一)
查看>>
setup facatory9.0打包详细教程(含静默安装和卸载)
查看>>
java.security.InvalidKeyException: Illegal key size
查看>>
Linux kernel pwn --- CSAW2015 StringIPC
查看>>
IDEA 找不到 Persistence窗口解决办法
查看>>
C++ Primer Plus读书笔记:循环读取(错误处理)
查看>>
Form窗体属性
查看>>
vue 错误收集
查看>>
00010.02最基础客户信息管理软件(意义类的小项目,练习基础,不涉及数据库)
查看>>