题目链接:POJ 2112 Optimal Milking

Optimal Milking
Time Limit: 2000MS   Memory Limit: 30000K
Total Submissions: 12446   Accepted: 4494
Case Time Limit: 1000MS

Description

FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) cows. A set of paths of various lengths runs among the cows and the milking machines. The milking machine locations are named by ID numbers 1..K; the cow locations are named by ID numbers K+1..K+C.

Each milking point can "process" at most M (1 <= M <= 15) cows each day.

Write a program to find an assignment for each cow to some milking machine so that the distance the furthest-walking cow travels is minimized (and, of course, the milking machines are not overutilized). At least one legal assignment is possible for all input data sets. Cows can traverse several paths on the way to their milking machine.

Input

* Line 1: A single line with three space-separated integers: K, C, and M.

* Lines 2.. ...: Each of these K+C lines of K+C space-separated integers describes the distances between pairs of various entities. The input forms a symmetric matrix. Line 2 tells the distances from milking machine 1 to each of the other entities; line 3 tells the distances from machine 2 to each of the other entities, and so on. Distances of entities directly connected by a path are positive integers no larger than 200. Entities not directly connected by a path have a distance of 0. The distance from an entity to itself (i.e., all numbers on the diagonal) is also given as 0. To keep the input lines of reasonable length, when K+C > 15, a row is broken into successive lines of 15 numbers and a potentially shorter line to finish up a row. Each new row begins on its own line.

Output

A single line with a single integer that is the minimum possible total distance for the furthest walking cow. 

Sample Input

2 3 2
0 3 2 1 1
3 0 3 2 0
2 3 0 1 0
1 2 1 0 2
1 0 0 2 0

Sample Output

2

Source

USACO 2003 U S Open

题意:

K个挤奶器(编号1~K),每个每天最多挤M头奶牛。共有C头奶牛(编号K+1~K+C)。挤奶器和奶牛间有不同长度的路。

编写程序,寻找一个方案,安排每头牛到某个挤奶器挤奶,并使得C头奶牛需要走的所有路程的最大路程最小。

分析:

因为有多个挤奶器和多头奶牛,因而要求最短路需要Floyd。然后用最大流算法求解;搜索最大距离的最小值采用二分枚举。

关键问题是构图:

构图思路:

(1)以0为源点s,n+1为汇点t。

(2)s向每头奶牛引一条边,容量为1,代表s走向每头奶牛的最大奶牛数。

(3)每个挤奶器向t引一条边,容量为M,代表每个挤奶器最多向t走M头奶牛。

(4)对于每头奶牛通向每个挤奶器的最短路,如果小于枚举当前距离,说明能够走到,那么从奶牛到挤奶器引一条边,容量为1。

(5)构图完毕。

最大流:

最大流可以用三种方法实现:

(1)EK,普通的SAP算法,因要不断BFS,复杂度较高:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;#define maxn 1010
#define INF 0x3f3f3f3f
int s, t, n, K, C, M;
int a[maxn], pre[maxn];
int flow[maxn][maxn];
int cap[maxn][maxn], mp[maxn][maxn];int EK()
{queue<int> q;memset(flow, 0, sizeof(flow));int ans = 0;while(1){memset(a, 0, sizeof(a));a[s] = INF;q.push(s);while(!q.empty())   //bfs找增广路径{int u = q.front();q.pop();for(int v = 1; v <= n; v++)if(!a[v] && cap[u][v] > flow[u][v]){pre[v] = u;q.push(v);a[v] = min(a[u], cap[u][v]-flow[u][v]);}}if(a[t] == 0) break;for(int u = t; u != s; u = pre[u])  //改进网络流{flow[pre[u]][u] += a[t];flow[u][pre[u]] -= a[t];}ans += a[t];}return ans;
}
void Floyd()
{for(int k = 1; k <= n; k++)for(int i = 1; i <= n; i++) {if(mp[i][k] != INF)for(int j = 1; j <= n; j++)mp[i][j] = min(mp[i][j], mp[i][k]+mp[k][j]);}
}
void build(int mid)
{n = K+C;memset(cap, 0, sizeof(cap));for(int i = K+1; i <= n; i++)cap[s][i] = 1;for(int i = 1; i <= K; i++)cap[i][t] = M;for(int i = K+1; i <= n; i++)for(int j = 1; j <= K; j++)if(mp[i][j] <= mid)cap[i][j] = 1;n = K+C+2;
}
void Solve()
{s = 0, t = n+1;int l = 0, r = 10000;while(l < r){int mid = (l+r)/2;build(mid);int ans = EK();if(ans >= C) r = mid;else l = mid+1;}printf("%d\n", r);
}
int main()
{//freopen("poj_2112.txt", "r", stdin);while(~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", &mp[i][j]);if(mp[i][j] == 0) mp[i][j] = INF;}Floyd();Solve();}return 0;
}

(2)Dinic,SAP的一种优化方案,保存层次网络,用DFS增广更加快速。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;#define maxn 250
#define INF 0x3f3f3f3fstruct Edge
{int from, to, cap;
};vector<Edge> EG;
vector<int> G[maxn];
int n, s, t, d[maxn], cur[maxn], mp[maxn][maxn];
int K, C, M;
void addEdge(int from, int to, int cap)
{EG.push_back((Edge){from, to, cap});EG.push_back((Edge){to, from, 0});int x = EG.size();G[from].push_back(x-2);G[to].push_back(x-1);
}bool bfs()
{memset(d, -1, sizeof(d));queue<int> q;q.push(s);d[s] = 0;while(!q.empty()){int x = q.front();q.pop();for(int i = 0; i < G[x].size(); i++){Edge& e = EG[G[x][i]];if(d[e.to] == -1 && e.cap > 0){d[e.to] = d[x]+1;q.push(e.to);}}}return (d[t]!=-1);
}int dfs(int x, int a)
{if(x == t || a == 0) return a;int flow = 0, f;for(int& i = cur[x]; i < G[x].size(); i++){Edge& e = EG[G[x][i]];if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap))) > 0){e.cap -= f;EG[G[x][i]^1].cap += f;flow += f;a -= f;if(a == 0) break;}}return flow;
}
int Dinic()
{int ans = 0;while(bfs()){memset(cur, 0, sizeof(cur));ans += dfs(s, INF);}EG.clear();for(int i = 0; i < n; ++i)G[i].clear();return ans;
}
void Floyd()
{for(int k = 1; k <= n; k++)for(int i = 1; i <= n; i++) {if(mp[i][k] != INF)for(int j = 1; j <= n; j++)mp[i][j] = min(mp[i][j], mp[i][k]+mp[k][j]);}
}
void build(int mid)
{n = K+C;for(int i = K+1; i <= n; i++)addEdge(s, i, 1);for(int i = 1; i <= K; i++)addEdge(i, t, M);for(int i = K+1; i <= n; i++)for(int j = 1; j <= K; j++)if(mp[i][j] <= mid)addEdge(i, j, 1);n = K+C+2;
}
void Solve()
{s = 0, t = n+1;int l = 0, r = 10000;while(l < r){int mid = (l+r)/2;build(mid);int ans = Dinic();if(ans >= C) r = mid;else l = mid+1;}printf("%d\n", r);
}
int main()
{//freopen("poj_2112.txt", "r", stdin);while(~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", &mp[i][j]);if(mp[i][j] == 0) mp[i][j] = INF;}Floyd();Solve();}return 0;
}

(3)ISAP,改进SAP,更加优化,活用层次网络,只需要一遍BFS,然后进行增广。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;#define maxn 250
#define INF 0x3f3f3f3fstruct Edge
{int from, to, cap, flow;
};vector<Edge> EG;
vector<int> G[maxn];
int n, s, t, d[maxn], cur[maxn], p[maxn], num[maxn], mp[maxn][maxn];
bool vis[maxn];
int K, C, M;void addEdge(int from, int to, int cap)
{EG.push_back((Edge){from, to, cap, 0});EG.push_back((Edge){to, from, 0, 0});int x = EG.size();G[from].push_back(x-2);G[to].push_back(x-1);
}void bfs()
{memset(vis, false, sizeof(vis));queue<int> q;vis[t] = true;d[t] = 0;q.push(t);while(!q.empty()) {int x = q.front();q.pop();for(int i = 0; i < G[x].size(); i++) {Edge& e = EG[G[x][i]^1];if(!vis[e.from] && e.cap > e.flow) {vis[e.from] = true;d[e.from] = d[x]+1;q.push(e.from);}}}
}int augment()
{int x = t, a = INF;while(x != s) {Edge& e = EG[p[x]];a = min(a, e.cap-e.flow);x = EG[p[x]].from;}x = t;while(x != s) {EG[p[x]].flow += a;EG[p[x]^1].flow -= a;x = EG[p[x]].from;}return a;
}
int ISAP()
{int ans =0;bfs();memset(num, 0, sizeof(num));for(int i = 0; i < n; i++)num[d[i]]++;int x = s;memset(cur, 0, sizeof(cur));while(d[s] < n) {if(x == t) {ans += augment();x = s;}bool flag = false;for(int i = cur[x]; i < G[x].size(); i++) {Edge& e = EG[G[x][i]];if(e.cap > e.flow && d[x] == d[e.to]+1) {flag = true;p[e.to] = G[x][i];cur[x] = i;x = e.to;break;}}if(!flag) {int m = n-1;for(int i = 0; i < G[x].size(); i++) {Edge& e = EG[G[x][i]];if(e.cap > e.flow)m = min(m, d[e.to]);}if(--num[d[x]] == 0) break;num[d[x] = m+1]++;cur[x] = 0;if(x != s)x = EG[p[x]].from;}}EG.clear();for(int i = 0; i < n; ++i)G[i].clear();return ans;
}void Floyd()
{for(int k = 1; k <= n; k++)for(int i = 1; i <= n; i++) {if(mp[i][k] != INF)for(int j = 1; j <= n; j++)mp[i][j] = min(mp[i][j], mp[i][k]+mp[k][j]);}
}
void build(int mid)
{n = K+C;for(int i = K+1; i <= n; i++)addEdge(s, i, 1);for(int i = 1; i <= K; i++)addEdge(i, t, M);for(int i = K+1; i <= n; i++)for(int j = 1; j <= K; j++)if(mp[i][j] <= mid)addEdge(i, j, 1);n = K+C+2;
}
void Solve()
{s = 0, t = n+1;int l = 0, r = 10000;while(l < r){int mid = (l+r)/2;build(mid);int ans = ISAP();if(ans >= C) r = mid;else l = mid+1;}printf("%d\n", r);
}
int main()
{//freopen("poj_2112.txt", "r", stdin);while(~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", &mp[i][j]);if(mp[i][j] == 0) mp[i][j] = INF;}Floyd();Solve();}return 0;
}

时间比较:

前两个分别为EK和ISAP算法,后面的为Dinic。不知为何我写的ISAP时间要比Dinic总是慢那么一点点,不过能顺利过题目就好了。

可以看出EK效率多差了吧:

Run ID User Problem Result Memory Time Language Code Length Submit Time
13475128 xxx 2112 Accepted 9584K 1875MS G++ 2266B 2014-09-25 02:39:13
13475120 xxx 2112 Accepted 1328K 157MS G++ 3678B 2014-09-25 02:35:15
13475117 xxx 2112 Accepted 1236K 125MS G++ 2812B 2014-09-25 02:33:48
13475113 xxx 2112 Accepted 1236K 141MS G++ 2814B 2014-09-25 02:33:09
13475102 xxx 2112 Accepted 1236K 94MS G++ 2814B 2014-09-25 02:26:43

POJ 2112 Optimal Milking 最优挤奶方案 Floyd算法+二分查找+最大流相关推荐

  1. POJ 2112 Optimal Milking(二分+最大流)

    POJ 2112 Optimal Milking 题目链接 题意:给定一些机器和奶牛,在给定距离矩阵,(不在对角线上为0的值代表不可达),每一个机器能容纳m个奶牛.问全部奶牛都能挤上奶,那么走的距离最 ...

  2. POJ 2112 Optimal Milking(二分图匹配)

    [题目链接] http://poj.org/problem?id=2112 [题目大意] 给出一些挤奶器,每台只能供给M头牛用,牛和挤奶器之间有一定的距离 现在要让每头牛都挤奶,同时最小化牛到挤奶器的 ...

  3. POJ - 2112 Optimal Milking(二分+二分图最大匹配-多重匹配(修改匈牙利实现)+Floyd求最短路)

    题目链接:点击查看 题目大意:给出n个牛奶机器,再给出m只奶牛,每个机器只能让最多k只牛一起挤奶,现在问如何分配奶牛,能让最远的那只奶牛到达机器的距离最小 题目分析:很综合的一道题目了,不算很难,但比 ...

  4. bzoj4094[Usaco2013 Dec]Optimal Milking最优挤奶

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4094 题目大意: 约翰有N 台挤奶机器,这些机器排成了一条直线,其中第i台机器工作效率是A ...

  5. poj 2112 Optimal Milking(二分+Floyd+最大流)

    题意:K个产奶机,C头奶牛,每个产奶机最多可供M头奶牛使用:并告诉了产奶机.奶牛之间的两两距离Dij(0<=i,j<K+C). 问题:如何安排使得在任何一头奶牛都有自己产奶机的条件下,奶牛 ...

  6. LeetCode LCP 28. 采购方案(排序 + 二分查找)

    文章目录 1. 题目 2. 解题 1. 题目 小力将 N 个零件的报价存于数组 nums. 小力预算为 target,假定小力仅购买两个零件,要求购买零件的花费不超过预算,请问他有多少种采购方案. 注 ...

  7. POJ 2785 有多少种4个数相加等于0的方案(二分查找 or hash)

    文章目录 1.二分查找法 1.1 思路: 1.2 AC代码 2.hash查找法 2.1 思路: 2.2 Wrong Answer 代码 2.3 Time Limit Exceeded 代码 2.4 偷 ...

  8. bzoj 4094: [Usaco2013 Dec]Optimal Milking

    4094: [Usaco2013 Dec]Optimal Milking Description Farmer John最近购买了N(1 <= N <= 40000)台挤奶机,编号为1 . ...

  9. 【BZOJ4094】[Usaco2013 Dec]Optimal Milking 线段树

    [BZOJ4094][Usaco2013 Dec]Optimal Milking Description Farmer John最近购买了N(1 <= N <= 40000)台挤奶机,编号 ...

  10. [bzoj4094][Usaco2013 Dec]Optimal Milking 线段树

    4094: [Usaco2013 Dec]Optimal Milking Time Limit: 10 Sec  Memory Limit: 128 MB [Submit][Status][Discu ...

最新文章

  1. Kubernetes日志分析利器:Elassandra部署使用指南
  2. 清华大学《操作系统》(九):进程和线程
  3. python+OpenCV检测条形码
  4. 常用的C++ STL
  5. 郁万玲:大数据时代的外贸精准营销
  6. 在linux下运行.o文件,Linux环境下在可执行程序中嵌入资源文件
  7. 常微分方程的数值解法
  8. Linux内核编程《一》
  9. 一个计算机爱好者的不完整回忆(十六)我的第一台电脑
  10. 做祛痘产品微信是如何引流的?祛斑祛痘产品引流加粉渠道有哪些?
  11. 2016.3.24 OneZero站立会议
  12. 个人经历:谈一谈的程序员求职途径
  13. 阿里云的图片在小程序内不显示
  14. M八七电影《新·奥特曼》主题曲歌手:米津玄師罗马音注释
  15. 利用Karabiner和键盘修饰键修改MAC键盘,实现打字时双手不离开字母和数字区
  16. 非递归实现二叉树的遍历
  17. 知识图到文本的生成——叁
  18. 如何布置环境?自己这边打版了,后台怎么打版才能创建活动?
  19. MySQL 中 CONCAT 函数使用
  20. 对话任正非:华为是一家全球化公司

热门文章

  1. win10 软路由_千元完美的家用低功耗软路由:J4125 迷你电脑GK41开箱体验!又是播放器,也是服务型AIO!...
  2. 微信开放平台认证后怎么实现扫码登录功能
  3. LDA-线性判别分析
  4. kali制作钓鱼网站
  5. js函数传参传入对象
  6. IDEA更改编码颜色/主题
  7. linux mbr gpt 区别,MBR、GPT的结构和区别
  8. 从实验开始零基础学网络路由交换 十一,配置直连路由
  9. 三层交换技术与链路聚合
  10. word生成html目录树,word将自定义目录做成模板