POJ2112_Optimal Milking_最大流解决匹配问题
来源:互联网 发布:9.3越狱软件源 编辑:程序博客网 时间:2024/06/08 17:07
题意
有 K 台机器和 C 头牛,可以抽象成 K + C 个点。给出所有点之间的直接路径的距离,用邻接矩阵表示,不存在的路径和点与自身的路径用 0 表示。每一头牛要匹配一台机器,每一台机器至多匹配 M 头牛,题目保证每一头牛都能匹配上一台机器。求最佳匹配方案,使跑路最远的牛跑的路最短。
思路
首先看到问题使最小化最大值,于是便想到了二分枚举法。于是,怎么检验答案呢。
看到机器与牛有对应关系,并且机器有一个容量,从而想到了网络流的做法。具体算法过程如下:
1.预处理
读入邻接矩阵后,用 floyd 算法求出每一点到其他所有点的最短路。注意 i == j 时的处理,并且因为 0 的存在,这里可以剪枝。(AC代码中的 floyd 函数就是加入了剪枝的)。
2.二分答案
以 0 为下界,inf 为上界进行二分枚举(可以从 floyd 中返回最长路径加以优化)。然后检验最大流是否等于牛的数量。以下假设当前枚举的答案为 x。
3.建图
设一个源点和一个汇点。
从原点出发向每一台机器连一条边,容量为 M。
从每一头牛出发向汇点连一条边,容量为1(每头牛只能匹配一台机器,为此wa了好几次)。
从每一台机器出发,向它能到达的牛连一条边,容量为1。能到达的意思是,距离小于 x 的,距离大于 x 的直接忽略,不用连边。
注意
因为 x 的值对图的影响,每一次二分枚举都要重新建图。
4.Dinic 算法求最大流
PS
这个题还可以用二分图的多重匹配做,即把每一个点分裂成 M 个点,然后进行二分图匹配。
题目链接
http://poj.org/problem?id=2112
AC代码
#include<cstdio>#include<iostream>#include<vector>#include<queue>#include<cstring>using namespace std;struct edge{ int to, cap, rev; edge(int a, int b, int c) :to(a), cap(b), rev(c) {}};const int maxn = 250;const int inf = 70000;int K, C, M;int n;vector<edge>G[maxn];int Map[maxn][maxn];int level[maxn];int iter [maxn];void floyd(){ for(int k= 1; k<= n; k++) for(int i= 1; i<= n; i++) if(Map[i][k] != inf) for(int j= 1; j<= n; j++) if(Map[k][j] != inf) Map[i][j] = min(Map[i][j], Map[i][k] + Map[k][j]);}void Add(int from, int to, int cap){ G[from].push_back(edge(to, cap, G[to].size())); G[to].push_back(edge(from, 0, G[from].size() - 1));}void bfs(int s){ memset(level, -1, sizeof level); level[s] = 0; queue<int> qu; qu.push(s); while(qu.size()) { int v = qu.front();qu.pop(); for(int i= 0; i< G[v].size(); i++) { edge e = G[v][i]; if(e.cap > 0 && level[e.to] < 0) { level[e.to] = level[v] + 1; qu.push(e.to); } } }}int dfs(int v, int t, int f){ if(v == t) return f; for(int &i= iter[v]; i< G[v].size(); i++) { edge &e = G[v][i]; if(e.cap > 0 && level[e.to] > level[v]) { int d = dfs(e.to, t, min(f, e.cap)); if(d > 0) { e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0;}int max_flow(int s, int t){ int flow = 0; while(1) { bfs(s); if(level[t] < 0) return flow; memset(iter, 0, sizeof iter); while(1) { int f = dfs(s, t, inf); if(f == 0) break; flow += f; } }}void init(int s, int t, int x){ for(int i= s; i<= t; i++) G[i].clear(); for(int i= 1; i<= K; i++) Add(s, i, M); for(int i= K+1; i<= n; i++) Add(i, t, 1); for(int i= 1; i<= K; i++) for(int j= K+1; j<= n; j++) { if(Map[i][j] > x) continue; Add(i, j, 1); }}bool Judge(int x){ int s = 0, t = n + 1; init(s, t, x); return max_flow(s, t) >= C;}int main(){ scanf("%d %d %d", &K, &C, &M); n = K + C; for(int i= 1; i<= n; i++) for(int j= 1; j<= n; j++) { scanf("%d", &Map[i][j]); if(Map[i][j] == 0) Map[i][j] = inf; } floyd(); int lb = 0, ub = inf; while(lb <= ub) { int mid = (lb + ub) >> 1; if(Judge(mid)) ub = mid - 1; else lb = mid + 1; } cout << ub + 1 << endl; return 0;}
阅读全文
0 0
- POJ2112_Optimal Milking_最大流解决匹配问题
- POJ2112_Optimal Milking(网洛流最大流Dinic+最短路Flody+二分)
- poj 3281 Dining (最大流解决匹配问题)
- 匈牙利算法---解决最大匹配问题
- poj 3189(最大流解决多重匹配)
- 匈牙利算法—解决二分图最大匹配问题
- 最大字串匹配问题
- 最大二分匹配问题
- 图的匹配问题与最大流问题(一)
- 字符串的最大匹配问题
- poj 3041(最大匹配问题)
- 最大匹配问题 POJ 1274
- 最大二分匹配:最大“素数伴侣”问题
- 利用匈牙利算法&Hopcroft-Karp算法解决二分图中的最大二分匹配问题
- Hopcroft-Karp算法模板(解决二分图最大匹配问题)
- 网络流24题之五 圆桌问题 最大匹配
- 二分图最大匹配问题之网络流算法
- 刘汝佳紫书-EdmondsKarp算法解决最大流问题
- Java基础-files(2)
- Android7.0中文文档(API)--- ViewFlipper
- ios搜索(可实现模糊搜索 支持拼音检索 首字母等)
- IPC-信号量
- 面膜使用心得
- POJ2112_Optimal Milking_最大流解决匹配问题
- 详解应对平台高并发的分布式调度框架TBSchedule
- PostgreSQL间隔时间(单位:分钟)
- UISwitch控件修改大小。
- canvas实现方块运动
- 文章标题
- 基于单链表和基于环形队列的生产者消费者模型
- Android studio使用javah找不到类文件问题
- 针对实践(一)代码的修改