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

    你可能感兴趣的文章
    Openlayers高级交互(17/20):通过坐标显示多边形,计算出最大幅宽
    查看>>
    Openlayers高级交互(18/20):根据feature,将图形适配到最可视化窗口
    查看>>
    Openlayers高级交互(19/20): 地图上点击某处,列表中显示对应位置
    查看>>
    Openlayers高级交互(2/20):清除所有图层的有效方法
    查看>>
    Openlayers高级交互(20/20):超级数据聚合,页面不再混乱
    查看>>
    Openlayers高级交互(3/20):动态添加 layer 到 layerGroup,并动态删除
    查看>>
    Openlayers高级交互(4/20):手绘多边形,导出KML文件,可以自定义name和style
    查看>>
    Openlayers高级交互(5/20):右键点击,获取该点下多个图层的feature信息
    查看>>
    Openlayers高级交互(6/20):绘制某点,判断它是否在一个电子围栏内
    查看>>
    Openlayers高级交互(7/20):点击某点弹出窗口,自动播放视频
    查看>>
    Openlayers高级交互(8/20):选取feature,平移feature
    查看>>
    Openlayers高级交互(9/20):编辑图形(放缩、平移、变形、旋转),停止编辑
    查看>>
    Openlayers:DMS-DD坐标形式互相转换
    查看>>
    openlayers:圆孔相机根据卫星经度、纬度、高度、半径比例推算绘制地面的拍摄的区域
    查看>>
    OpenLDAP(2.4.3x)服务器搭建及配置说明
    查看>>
    OpenLDAP编译安装及配置
    查看>>
    Openmax IL (二)Android多媒体编解码Component
    查看>>
    OpenMCU(一):STM32F407 FreeRTOS移植
    查看>>
    OpenMCU(三):STM32F103 FreeRTOS移植
    查看>>
    OpenMCU(三):STM32F103 FreeRTOS移植
    查看>>