博客
关于我
[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/

    你可能感兴趣的文章
    NIO基于UDP协议的网络编程
    查看>>
    NISP一级,NISP二级报考说明,零基础入门到精通,收藏这篇就够了
    查看>>
    Nitrux 3.8 发布!性能全面提升,带来非凡体验
    查看>>
    NI笔试——大数加法
    查看>>
    NLog 自定义字段 写入 oracle
    查看>>
    NLog类库使用探索——详解配置
    查看>>
    NLP 基于kashgari和BERT实现中文命名实体识别(NER)
    查看>>
    NLP 项目:维基百科文章爬虫和分类【01】 - 语料库阅读器
    查看>>
    NLP_什么是统计语言模型_条件概率的链式法则_n元统计语言模型_马尔科夫链_数据稀疏(出现了词库中没有的词)_统计语言模型的平滑策略---人工智能工作笔记0035
    查看>>
    NLP学习笔记:使用 Python 进行NLTK
    查看>>
    NLP的神经网络训练的新模式
    查看>>
    NLP采用Bert进行简单文本情感分类
    查看>>
    NLP问答系统:使用 Deepset SQUAD 和 SQuAD v2 度量评估
    查看>>
    NLP:使用 SciKit Learn 的文本矢量化方法
    查看>>
    Nmap扫描教程之Nmap基础知识
    查看>>
    Nmap端口扫描工具Windows安装和命令大全(非常详细)零基础入门到精通,收藏这篇就够了
    查看>>
    NMAP网络扫描工具的安装与使用
    查看>>
    NMF(非负矩阵分解)
    查看>>
    nmon_x86_64_centos7工具如何使用
    查看>>
    NN&DL4.1 Deep L-layer neural network简介
    查看>>