题意 : 有 K 台挤奶机器,每台机器可以接受 M 头牛进行挤奶作业,总共有 C 头奶牛,机器编号为 1~K,奶牛编号为 K+1 ~ K+C ,然后给出奶牛和机器之间的距离矩阵,要求求出使得每头牛都能被安排到某一挤奶机且所有奶牛走出来的路径的最大值的最小值。

分析 : 一个比较复杂的最小化最大值问题,解题思路是二分路程花费,然后建图使用最大流判断可行性。当然还可以使用最小费用最大流,增广和最短路的松弛维护的就是路径上的最大值而不再是花费了。这里只讨论二分+最大流解法,最小费用最大流的坑以后再填........

其实这题的思路和 POJ 2391 差不多 ==> 解题报告

先将题目给出来的距离矩阵跑一下 Floyd 求出全源最短路方便后面建图,这里注意一下除了对角线的点若有其他点为 0 则应将其值设置为 INF 代表不可达

抽象出一个源点和汇点,然后给安排出 C 个点代表 C 头牛、安排 K 个点代表 K 个挤奶机器,将源点到牛所代表的 C 个点各连一条容量为 1 的边

然后二分答案,对于二分出来的花费我们可以根据 Floyd 跑出来的距离矩阵将牛与机器之间的符合条件的( 最短花费 <= 当前二分的花费 )边连上

最后将各个机器与汇点连一条容量为 M 的边,以达到限制每台机器只接受 M 头牛这一限制,最后跑一下最大流,如果最大流 == 牛的总数说明可行

  1. #include<stdio.h>
  2. #include<queue>
  3. #include<vector>
  4. #include<algorithm>
  5. #include<string.h>
  6. using namespace std;
  7. ;
  8. const int INF = 0x3f3f3f3f;
  9. int Dist[maxn][maxn];
  10. int K, C, M;
  11.  
  12. struct Edge
  13. {
  14. int from,to,cap,flow;
  15. Edge(){}
  16. Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
  17.  
  18. };
  19.  
  20. struct Dinic
  21. {
  22. int n,m,s,t; //结点数,边数(包括反向弧),源点与汇点编号
  23. vector<Edge> edges; //边表 edges[e]和edges[e^1]互为反向弧
  24. vector<int> G[maxn]; //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
  25. bool vis[maxn]; //BFS使用,标记一个节点是否被遍历过
  26. int d[maxn]; //d[i]表从起点s到i点的距离(层次)
  27. int cur[maxn]; //cur[i]表当前正访问i节点的第cur[i]条弧
  28.  
  29. void init(int n,int s,int t)
  30. {
  31. this->n=n,this->s=s,this->t=t;
  32. ;i<=n;i++) G[i].clear();
  33. edges.clear();
  34. }
  35.  
  36. void AddEdge(int from,int to,int cap)
  37. {
  38. edges.push_back( Edge() );
  39. edges.push_back( Edge(to,,) );
  40. m = edges.size();
  41. G[);
  42. G[to].push_back(m-);
  43. }
  44.  
  45. bool BFS()
  46. {
  47. memset(vis,,sizeof(vis));
  48. queue<int> Q;//用来保存节点编号的
  49. Q.push(s);
  50. d[s]=;
  51. vis[s]=true;
  52. while(!Q.empty())
  53. {
  54. int x=Q.front(); Q.pop();
  55. ; i<G[x].size(); i++)
  56. {
  57. Edge& e=edges[G[x][i]];
  58. if(!vis[e.to] && e.cap>e.flow)
  59. {
  60. vis[e.to]=true;
  61. d[e.to] = d[x]+;
  62. Q.push(e.to);
  63. }
  64. }
  65. }
  66. return vis[t];
  67. }
  68.  
  69. //a表示从s到x目前为止所有弧的最小残量
  70. //flow表示从x到t的最小残量
  71. int DFS(int x,int a)
  72. {
  73. //printf("%d %d\n", x, a);
  74. )return a;
  75. ,f;//flow用来记录从x到t的最小残量
  76. for(int& i=cur[x]; i<G[x].size(); i++)
  77. {
  78. Edge& e=edges[G[x][i]];
  79. ==d[e.to] && (f=DFS( e.to,min(a,e.cap-e.flow) ) )> )
  80. {
  81. e.flow +=f;
  82. edges[G[x][i]^].flow -=f;
  83. flow += f;
  84. a -= f;
  85. ) break;
  86. }
  87. }
  88. return flow;
  89. }
  90.  
  91. int Maxflow()
  92. {
  93. ;
  94. while(BFS())
  95. {
  96. memset(cur,,sizeof(cur));
  97. flow += DFS(s,INF);
  98. }
  99. return flow;
  100. }
  101. }DC;
  102.  
  103. bool OK(int Upper)
  104. {
  105. ;
  106. DC.init(N+, , N);
  107. ; i<=C; i++)
  108. DC.AddEdge(, K+i, );
  109. ; i<=K; i++)
  110. DC.AddEdge(i, N, M);
  111. ; i<=K+C; i++)
  112. ; j<=K; j++)
  113. if(Dist[i][j] <= Upper)
  114. DC.AddEdge(i, j, INF);
  115. return (DC.Maxflow() == C);
  116. }
  117.  
  118. int main(void)
  119. {
  120. while(~scanf("%d %d %d", &K, &C, &M)){
  121.  
  122. ; i<=K+C; i++)
  123. ; j<=K+C; j++){
  124. scanf("%d", &Dist[i][j]);
  125. )
  126. Dist[i][j] = INF;
  127. }
  128.  
  129. // for(int i=1; i<=K+C; i++){
  130. // for(int j=1; j<=K+C; j++){
  131. // printf("%d ", Dist[i][j]);
  132. // }puts("");
  133. // }puts("");
  134.  
  135. ; k<=K+C; k++)
  136. ; i<=K+C; i++)
  137. ; j<=K+C; j++)
  138. Dist[i][j] = min(Dist[i][j], Dist[i][k]+Dist[k][j]);
  139.  
  140. // for(int i=1; i<=K+C; i++){
  141. // for(int j=1; j<=K+C; j++){
  142. // printf("%d ", Dist[i][j]);
  143. // }puts("");
  144. // }puts("");
  145.  
  146. , FLOOR = INF;
  147. ; i<=K+C; i++)
  148. ; j<=K+C; j++){
  149. if(i==j) continue;
  150. if(Dist[i][j] == INF) continue;
  151. UPPER = max(UPPER, Dist[i][j]);
  152. FLOOR = min(FLOOR, Dist[i][j]);
  153. }
  154.  
  155. , mid;
  156. while(L <= R){
  157. mid = L + ((R-L)>>);
  158. ;
  159. ;
  160. }
  161.  
  162. printf("%d\n", ans);
  163. }
  164. ;
  165. }

瞎 : 之前是做过 POJ 2391 的,在思考这道题的时候大部分都能想出来,但是在具体实现的时候由于对此类解法的理解不够深厚,在写二分判断函数建边的时候我的代码如下

  1. bool OK(int Upper)
  2. {
  3. ;
  4. DC.init(N+, , N);
  5. ; i<=C; i++)
  6. DC.AddEdge(, K+i, );
  7. ; i<=K; i++)
  8. DC.AddEdge(i, N, M);
  9. ; i<=K+C; i++) ///这里我傻逼了......
  10. ; j<=K+C; j++)
  11. if(Dist[i][j] <= Upper)
  12. DC.AddEdge(i, j, INF);
  13. return (DC.Maxflow() == C);
  14. }

当时是理解为从源点出发,然后所有的边去和当前二分答案判断是否加上这一条边,这样牛与牛、机器与机器可能就会连上,因为牛可以通过去其他牛所在的地方去其他机器或者通过其他机器所在的点去另外的机器,也许更优!其实很傻逼......,我没有理解深刻,实际上让原本的矩阵去跑 Floyd 就是做这个事情的,所以跑完 Floyd 之后直接将我们让想要的牛与机器之间最短花费与二分花费去判断,最后连成的是一个二分图。如果按我错误的做法那么跑 Floyd 便失去了意义,多连上了牛和牛的或者机器和机器的那么就有可能使得有些不符合条件的边也被连上!下面举个例子:

假设 ① 是机器且可接纳两头牛,②、③ 都是牛,假设当前二分的花费为 2

如果按我的错误做法实际 ①、② 之间的最小距离为 3 应该不可达,而①、③可以

但是由于我全局地去连边即我会去判断②、③之间是否花费小于当前二分出来的 2

此时会发现②和③的边被连上了,如果这样去跑最大流会被判定为满流,但是实际不是

所以正确做法是跑完 Floyd 之后只考虑牛和机器就行了

让我意识到这一点的是下面这个例子,建议把图画出来,然后AC代码跑出了我认为不可能跑出的3

下面的例子则是我特意将牛和机器之间的距离放大,然后将一组牛牛距离变小

因为我认为正确代码它只考虑了牛和机器,所以不对,但是事实你也看到了,我傻逼了

2 3 3

0      0     2     0       2

0      0     0   100     0

2      0     0     1       0

0    100   1     0       0

2      0     0     0       0

ans = 3

POJ 2112 Optimal Milking ( 经典最大流 && Floyd && 二分 )的更多相关文章

  1. POJ 2112—— Optimal Milking——————【多重匹配、二分枚举答案、floyd预处理】

    Optimal Milking Time Limit:2000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Sub ...

  2. POJ 2391 Ombrophobic Bovines ( 经典最大流 && Floyd && 二分 && 拆点建图)

    题意 : 给出一些牛棚,每个牛棚都原本都有一些牛但是每个牛棚可以容纳的牛都是有限的,现在给出一些路与路的花费和牛棚拥有的牛和可以容纳牛的数量,要求最短能在多少时间内使得每头牛都有安身的牛棚.( 这里注 ...

  3. POJ 2112 Optimal Milking(最大流)

    题目链接:http://poj.org/problem?id=2112 Description FJ has moved his K (1 <= K <= 30) milking mach ...

  4. POJ 2112.Optimal Milking (最大流)

    时间限制:2s 空间限制:30M 题意: 有K台挤奶机(编号1~K),C头奶牛(编号K+1~K+C),给出各点之间距离.现在要让C头奶牛到挤奶机去挤奶,每台挤奶机只能处理M头奶牛,求使所走路程最远的奶 ...

  5. POJ 2112 Optimal Milking 【网络流】【二分】【最短路】

    题意: k c m 分别代表挤奶机数量,牛数量,和挤奶机容量. 接下来(n=k+c)n*n的矩阵A,代表挤奶机或者牛的距离,如果对角线都为0,如果非对角线没有直接路相连也为0. 1 <= K & ...

  6. POJ 2112 Optimal Milking (二分 + floyd + 网络流)

    POJ 2112 Optimal Milking 链接:http://poj.org/problem?id=2112 题意:农场主John 将他的K(1≤K≤30)个挤奶器运到牧场,在那里有C(1≤C ...

  7. POJ 2112 Optimal Milking (二分+最短路径+网络流)

    POJ  2112 Optimal Milking (二分+最短路径+网络流) Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K To ...

  8. Poj 2112 Optimal Milking (多重匹配+传递闭包+二分)

    题目链接: Poj 2112 Optimal Milking 题目描述: 有k个挤奶机,c头牛,每台挤奶机每天最多可以给m头奶牛挤奶.挤奶机编号从1到k,奶牛编号从k+1到k+c,给出(k+c)*(k ...

  9. POJ 2112 Optimal Milking (Dinic + Floyd + 二分)

    Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 19456   Accepted: 6947 ...

随机推荐

  1. 获取当前页面的title

    #-*-coding:utf-8-*-from selenium import webdriverdriver = webdriver.Firefox()driver.get("https: ...

  2. TCP/IP协议-1

    转载资源,链接地址https://www.cnblogs.com/evablogs/p/6709707.html

  3. APIView的流程分析

     APIView的流程分析 1.入口,因为视图类的继承APIView()的 as_view()是一个绑定类的方法 2.进入as_view(),正好这个as_view()有个返回值 返回的是dispat ...

  4. IntelliJ IDEA 2019.3 这回真的要飞起来了,新特性抢先看!

    IntelliJ IDEA 才公布下一个主要版本 2019.3 的 Roadmap,近日就发布了 IntelliJ IDEA 2019.3 的首个早期访问版本(即 EAP 版本),版本号为 2019. ...

  5. 【LGR-063】洛谷11月月赛 I & MtOI2019 Ex Div.2

    [MtOI2019]黑蚊子多: 送分向水题,直接模拟即可. #include<iostream> #include<cstdio> #define N 1505 using n ...

  6. Hyper-V Centos7 虚拟机固定IP

    在网上看到很多篇文章,自己也去试验过,结果实现的效果都不是很理想,并不是自己所需要的,下面是我自己研究,最后成功的经验,希望能够帮到大家.少走一些弯路. 需求 1.无论物理机的网络环境怎么变化,都需要 ...

  7. HNUST-1681 机器人走格子(找规律)

    1681: 机器人走格子 时间限制: 1 Sec  内存限制: 128 MB提交: 244  解决: 58[提交][状态][讨论版] 题目描述 一个长X宽Y的棋盘,有XY个格子.将机器人放在某个格子中 ...

  8. bzoj4103 [Thu Summer Camp 2015]异或运算(可持久化trie)

    内存限制:512 MiB 时间限制:1000 ms 题目描述 给定长度为n的数列X={x1,x2,...,xn}和长度为m的数列Y={y1,y2,...,ym},令矩阵A中第i行第j列的值Aij=xi ...

  9. angularJS(一):表达式、指令

    简介 以 JavaScript 编写的库,是一个 JavaScript 框架 一.表达式 AngularJS 使用 表达式 把数据绑定到 HTML. 表达式写在双大括号内:{{ expression ...

  10. 剑指offer-python-回溯法-矩阵中的路径

    这个系列主要详细记录代码详解的过程. 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格 ...