博客
关于我
[SCOI2015]小凸玩矩阵 (匈牙利+二分)
阅读量:294 次
发布时间:2019-03-03

本文共 2903 字,大约阅读时间需要 9 分钟。

为了解决这个问题,我们需要找到从给定矩阵中选出的 N 个数中第 K 大的数的最小值。我们可以使用二分查找来确定这个最小值,并结合最大匹配算法来检查每个中间值是否满足条件。

方法思路

  • 问题分析:我们需要从矩阵中选出 N 个数,这些数不能在同一行或同一列。目标是找到选出的 N 个数中第 K 大的数的最小值。
  • 二分查找:我们使用二分查找来确定这个最小值。每次取中间值 mid,检查是否存在一种选法,使得选出的 N 个数中至少有 N-K+1 个数小于等于 mid
  • 最大匹配:对于每个中间值 mid,我们构造一个二分图,其中边的存在条件是矩阵中的元素小于等于 mid。然后使用最大流算法(Dinic算法)来检查是否存在一个足够大的匹配。
  • 解决代码

    #include 
    #include
    #include
    #include
    #include
    using namespace std;class Edge { public: int to; int rev; int capacity; Edge(int to, int rev, int capacity) : to(to), rev(rev), capacity(capacity) {}};vector
    > graph;int max_flow = 0;void add_edge(int u, int v, int cap) { graph[u].push_back(Edge(v, graph[v].size(), cap)); graph[v].push_back(Edge(u, graph[u].size()-1, 0));}void bfs_level(int s, int t, vector
    & level) { queue
    q; level[s] = 0; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for (auto& e : graph[u]) { if (level[e.to] == -1 && e.capacity > 0) { level[e.to] = level[u] + 1; q.push(e.to); } } }}void dfs_flow(int u, int t, int flow, vector
    & ptr, vector
    & level, vector
    & ptr_edge) { if (u == t) return flow; for (int i = 0; i < ptr[u]; i++) { int e = graph[u][i]; if (e.capacity > 0 && level[u] < level[e.to]) { int min_flow = min(flow, e.capacity); int result = dfs_flow(e.to, t, min_flow, ptr, level, ptr_edge); if (result > 0) { e.capacity -= result; graph[e.to][ptr_edge[e.to]].capacity += result; return result; } } } return 0;}int max_flow_dinic(int s, int t) { vector
    level; while (true) { bfs_level(s, t, level); if (level[t] == -1) return max_flow; vector
    ptr(graph.size()); while (true) { int f = dfs_flow(s, t, INT_MAX, ptr, level, ptr_edge); if (f == 0) break; max_flow += f; } }}int main() { int n, m, k; scanf("%d %d %d", &n, &m, &k); vector
    > matrix(n, vector
    (m)); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { int val; scanf("%d", &val); matrix[i][j] = val; } } int max_val = INT_MAX; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (matrix[i][j] > max_val) max_val = matrix[i][j]; } } int low = 1, high = max_val, ans = max_val; required = n - k + 1; while (low <= high) { mid = (low + high) >> 1; int size = n + m + 2; graph.resize(size); for (int i = 0; i < size; ++i) { graph[i].clear(); } for (int i = 1; i <= n; ++i) { add_edge(0, i, 1); } for (int j = 1; j <= m; ++j) { add_edge(n+1 + j -1, size-1, 1); } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (matrix[i-1][j-1] <= mid) { add_edge(i, n+1 + j-1, 1); } } } int f = max_flow_dinic(0, size-1); if (f >= required) { ans = mid; high = mid - 1; } else { low = mid + 1; } } cout << ans << endl; return 0;}

    代码解释

  • Edge 类:用于表示图中的边,包含目标顶点、反向边指针和容量。
  • add_edge 函数:添加边到图中,构建邻接表。
  • bfs_level 函数:使用 BFS 计算顶点的层次,用于找出可行流路径。
  • dfs_flow 函数:使用 DFS 寻找增广路径,增加流的流动。
  • max_flow_dinic 函数:Dinic算法的实现,计算最大流。
  • 主函数:读取输入,设置初始范围,进行二分查找,构造图并调用最大流算法,输出结果。
  • 转载地址:http://eail.baihongyu.com/

    你可能感兴趣的文章
    nodejs与javascript中的aes加密
    查看>>
    nodejs中Express 路由统一设置缓存的小技巧
    查看>>
    nodejs中express的使用
    查看>>
    Nodejs中的fs模块的使用
    查看>>
    NodeJS使用淘宝npm镜像站的各种姿势
    查看>>
    nodejs包管理工具对比:npm、Yarn、cnpm、npx
    查看>>
    NodeJs单元测试之 API性能测试
    查看>>
    nodejs图片转换字节保存
    查看>>
    nodejs在Liunx上的部署生产方式-PM2
    查看>>
    nodejs字符与字节之间的转换
    查看>>
    NodeJs学习笔记001--npm换源
    查看>>
    NodeJs学习笔记002--npm常用命令详解
    查看>>
    nodejs学习笔记一——nodejs安装
    查看>>
    NodeJS实现跨域的方法( 4种 )
    查看>>
    nodejs封装http请求
    查看>>
    nodejs常用组件
    查看>>
    nodejs开发公众号报错 40164,白名单配置找不到,竟然是这个原因
    查看>>
    Nodejs异步回调的处理方法总结
    查看>>
    NodeJS报错 Fatal error: ENOSPC: System limit for number of file watchers reached, watch ‘...path...‘
    查看>>
    Nodejs教程09:实现一个带接口请求的简单服务器
    查看>>