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

本文共 2922 字,大约阅读时间需要 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/

    你可能感兴趣的文章
    Node提示:error code Z_BUF_ERROR,error error -5,error zlib:unexpected end of file
    查看>>
    Node提示:npm does not support Node.js v12.16.3
    查看>>
    Node搭建静态资源服务器时后缀名与响应头映射关系的Json文件
    查看>>
    Node服务在断开SSH后停止运行解决方案(创建守护进程)
    查看>>
    node模块化
    查看>>
    node模块的本质
    查看>>
    node环境下使用import引入外部文件出错
    查看>>
    node环境:Error listen EADDRINUSE :::3000
    查看>>
    Node的Web应用框架Express的简介与搭建HelloWorld
    查看>>
    Node第一天
    查看>>
    node编译程序内存溢出
    查看>>
    Node读取并输出txt文件内容
    查看>>
    node防xss攻击插件
    查看>>
    noi 1996 登山
    查看>>
    noi 7827 质数的和与积
    查看>>
    NOI-1.3-11-计算浮点数相除的余数
    查看>>
    noi.ac #36 模拟
    查看>>
    NOI2010 海拔(平面图最大流)
    查看>>
    NOIp2005 过河
    查看>>
    NOIP2011T1 数字反转
    查看>>