POJ 2112 Optimal Milking ( 经典最大流 && Floyd && 二分 )
题意 : 有 K 台挤奶机器,每台机器可以接受 M 头牛进行挤奶作业,总共有 C 头奶牛,机器编号为 1~K,奶牛编号为 K+1 ~ K+C ,然后给出奶牛和机器之间的距离矩阵,要求求出使得每头牛都能被安排到某一挤奶机且所有奶牛走出来的路径的最大值的最小值。
分析 : 一个比较复杂的最小化最大值问题,解题思路是二分路程花费,然后建图使用最大流判断可行性。当然还可以使用最小费用最大流,增广和最短路的松弛维护的就是路径上的最大值而不再是花费了。这里只讨论二分+最大流解法,最小费用最大流的坑以后再填........
其实这题的思路和 POJ 2391 差不多 ==> 解题报告
先将题目给出来的距离矩阵跑一下 Floyd 求出全源最短路方便后面建图,这里注意一下除了对角线的点若有其他点为 0 则应将其值设置为 INF 代表不可达
抽象出一个源点和汇点,然后给安排出 C 个点代表 C 头牛、安排 K 个点代表 K 个挤奶机器,将源点到牛所代表的 C 个点各连一条容量为 1 的边
然后二分答案,对于二分出来的花费我们可以根据 Floyd 跑出来的距离矩阵将牛与机器之间的符合条件的( 最短花费 <= 当前二分的花费 )边连上
最后将各个机器与汇点连一条容量为 M 的边,以达到限制每台机器只接受 M 头牛这一限制,最后跑一下最大流,如果最大流 == 牛的总数说明可行
#include<stdio.h>
#include<queue>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
;
const int INF = 0x3f3f3f3f;
int Dist[maxn][maxn];
int K, C, M;
struct Edge
{
int from,to,cap,flow;
Edge(){}
Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
};
struct Dinic
{
int n,m,s,t; //结点数,边数(包括反向弧),源点与汇点编号
vector<Edge> edges; //边表 edges[e]和edges[e^1]互为反向弧
vector<int> G[maxn]; //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn]; //BFS使用,标记一个节点是否被遍历过
int d[maxn]; //d[i]表从起点s到i点的距离(层次)
int cur[maxn]; //cur[i]表当前正访问i节点的第cur[i]条弧
void init(int n,int s,int t)
{
this->n=n,this->s=s,this->t=t;
;i<=n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap)
{
edges.push_back( Edge() );
edges.push_back( Edge(to,,) );
m = edges.size();
G[);
G[to].push_back(m-);
}
bool BFS()
{
memset(vis,,sizeof(vis));
queue<int> Q;//用来保存节点编号的
Q.push(s);
d[s]=;
vis[s]=true;
while(!Q.empty())
{
int x=Q.front(); Q.pop();
; i<G[x].size(); i++)
{
Edge& e=edges[G[x][i]];
if(!vis[e.to] && e.cap>e.flow)
{
vis[e.to]=true;
d[e.to] = d[x]+;
Q.push(e.to);
}
}
}
return vis[t];
}
//a表示从s到x目前为止所有弧的最小残量
//flow表示从x到t的最小残量
int DFS(int x,int a)
{
//printf("%d %d\n", x, a);
)return a;
,f;//flow用来记录从x到t的最小残量
for(int& i=cur[x]; i<G[x].size(); i++)
{
Edge& e=edges[G[x][i]];
==d[e.to] && (f=DFS( e.to,min(a,e.cap-e.flow) ) )> )
{
e.flow +=f;
edges[G[x][i]^].flow -=f;
flow += f;
a -= f;
) break;
}
}
return flow;
}
int Maxflow()
{
;
while(BFS())
{
memset(cur,,sizeof(cur));
flow += DFS(s,INF);
}
return flow;
}
}DC;
bool OK(int Upper)
{
;
DC.init(N+, , N);
; i<=C; i++)
DC.AddEdge(, K+i, );
; i<=K; i++)
DC.AddEdge(i, N, M);
; i<=K+C; i++)
; j<=K; j++)
if(Dist[i][j] <= Upper)
DC.AddEdge(i, j, INF);
return (DC.Maxflow() == C);
}
int main(void)
{
while(~scanf("%d %d %d", &K, &C, &M)){
; i<=K+C; i++)
; j<=K+C; j++){
scanf("%d", &Dist[i][j]);
)
Dist[i][j] = INF;
}
// for(int i=1; i<=K+C; i++){
// for(int j=1; j<=K+C; j++){
// printf("%d ", Dist[i][j]);
// }puts("");
// }puts("");
; k<=K+C; k++)
; i<=K+C; i++)
; j<=K+C; j++)
Dist[i][j] = min(Dist[i][j], Dist[i][k]+Dist[k][j]);
// for(int i=1; i<=K+C; i++){
// for(int j=1; j<=K+C; j++){
// printf("%d ", Dist[i][j]);
// }puts("");
// }puts("");
, FLOOR = INF;
; i<=K+C; i++)
; j<=K+C; j++){
if(i==j) continue;
if(Dist[i][j] == INF) continue;
UPPER = max(UPPER, Dist[i][j]);
FLOOR = min(FLOOR, Dist[i][j]);
}
, mid;
while(L <= R){
mid = L + ((R-L)>>);
;
;
}
printf("%d\n", ans);
}
;
}
瞎 : 之前是做过 POJ 2391 的,在思考这道题的时候大部分都能想出来,但是在具体实现的时候由于对此类解法的理解不够深厚,在写二分判断函数建边的时候我的代码如下
bool OK(int Upper)
{
;
DC.init(N+, , N);
; i<=C; i++)
DC.AddEdge(, K+i, );
; i<=K; i++)
DC.AddEdge(i, N, M);
; i<=K+C; i++) ///这里我傻逼了......
; j<=K+C; j++)
if(Dist[i][j] <= Upper)
DC.AddEdge(i, j, INF);
return (DC.Maxflow() == C);
}
当时是理解为从源点出发,然后所有的边去和当前二分答案判断是否加上这一条边,这样牛与牛、机器与机器可能就会连上,因为牛可以通过去其他牛所在的地方去其他机器或者通过其他机器所在的点去另外的机器,也许更优!其实很傻逼......,我没有理解深刻,实际上让原本的矩阵去跑 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 && 二分 )的更多相关文章
- POJ 2112—— Optimal Milking——————【多重匹配、二分枚举答案、floyd预处理】
Optimal Milking Time Limit:2000MS Memory Limit:30000KB 64bit IO Format:%I64d & %I64u Sub ...
- POJ 2391 Ombrophobic Bovines ( 经典最大流 && Floyd && 二分 && 拆点建图)
题意 : 给出一些牛棚,每个牛棚都原本都有一些牛但是每个牛棚可以容纳的牛都是有限的,现在给出一些路与路的花费和牛棚拥有的牛和可以容纳牛的数量,要求最短能在多少时间内使得每头牛都有安身的牛棚.( 这里注 ...
- POJ 2112 Optimal Milking(最大流)
题目链接:http://poj.org/problem?id=2112 Description FJ has moved his K (1 <= K <= 30) milking mach ...
- POJ 2112.Optimal Milking (最大流)
时间限制:2s 空间限制:30M 题意: 有K台挤奶机(编号1~K),C头奶牛(编号K+1~K+C),给出各点之间距离.现在要让C头奶牛到挤奶机去挤奶,每台挤奶机只能处理M头奶牛,求使所走路程最远的奶 ...
- POJ 2112 Optimal Milking 【网络流】【二分】【最短路】
题意: k c m 分别代表挤奶机数量,牛数量,和挤奶机容量. 接下来(n=k+c)n*n的矩阵A,代表挤奶机或者牛的距离,如果对角线都为0,如果非对角线没有直接路相连也为0. 1 <= K & ...
- POJ 2112 Optimal Milking (二分 + floyd + 网络流)
POJ 2112 Optimal Milking 链接:http://poj.org/problem?id=2112 题意:农场主John 将他的K(1≤K≤30)个挤奶器运到牧场,在那里有C(1≤C ...
- POJ 2112 Optimal Milking (二分+最短路径+网络流)
POJ 2112 Optimal Milking (二分+最短路径+网络流) Optimal Milking Time Limit: 2000MS Memory Limit: 30000K To ...
- Poj 2112 Optimal Milking (多重匹配+传递闭包+二分)
题目链接: Poj 2112 Optimal Milking 题目描述: 有k个挤奶机,c头牛,每台挤奶机每天最多可以给m头奶牛挤奶.挤奶机编号从1到k,奶牛编号从k+1到k+c,给出(k+c)*(k ...
- POJ 2112 Optimal Milking (Dinic + Floyd + 二分)
Optimal Milking Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 19456 Accepted: 6947 ...
随机推荐
- CSS3——对齐 组合选择符 伪类 伪元素 导航栏 下拉菜单
水平&垂直对齐 元素居中对齐 .center { margin: auto; width: 50%; border: 3px solid green; padding: 10px; } 文本 ...
- 汇编语言——DOSBox 学习网址整理
汇编语言--使用DOSBox写一个HelloWorld https://blog.csdn.net/whatiwhere/article/details/8035910 windows下汇编工具--d ...
- 【HANA系列】SAP HANA SQL获取上周的周一
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL获取上周 ...
- 图解 SQL 里的各种 JOIN
约定 下文将使用两个数据库表 Table_A 和 Table_B 来进行示例讲解,其结构与数据分别如下: mysql> SELECT * FROM Table_A ORDER BY PK ASC ...
- Java数据结构之栈(Stack)
1.栈(Stack)的介绍 栈是一个先入后出(FILO:First In Last Out)的有序列表. 栈(Stack)是限制线性表中元素的插入和删除只能在同一端进行的一种特殊线性表. 允许插入和删 ...
- 02:django model数据库操作
Django其他篇 目录: 1.1 Django中使用MySQL 1.2 创建表 1.3 Django一对多表结构操作 1.4 Django多对多表结构操作 1.5 一大波Model操作 1.6 Mo ...
- org.apache.httpcomponents:httpclient 工具类
基于httpclient 版本4.4.1 因为http连接需要三次握手,在需要频繁调用时浪费资源和时间 故采用连接池的方式连接 根据实际需要更改 连接池最大连接数.路由最大连接数 另一个需要注意的是 ...
- selenium 教程
selenium 本身是一套web自动化测试工具,但其经常被用于爬虫,解决一些复杂爬虫的问题. selenium 用于爬虫时,相当于模拟人操作浏览器. 浏览器驱动 使用 selenium 需要先安装 ...
- js模拟自动化测试 -- 多用户登录
1.核心登录提交方法 /** * 动态表单提交方法 * @param url{string}: 提交地址 * @param params{object}: 要提交的表单数据 **/ function ...
- vue编写轮播图组件
<template> <div id="slider"> <div class="window" @mouseover=& ...