poj_2112 网络最大流+二分法
题目大意
有K台挤奶机和C头奶牛,都被视为物体,这K+C个物体之间存在路径。给出一个 (K+C)x(K+C) 的矩阵A,A[i][j]表示物体i和物体j之间的距离,有些物体之间可能没有直接通路。
每台挤奶机可以容纳m头奶牛去挤奶,且每个奶牛仅可以去往一台挤奶机。现在安排这C头奶牛去挤奶,每头奶牛会去往某个挤奶机,求出这C头奶牛去其对应挤奶机的路径长度的最大值的最小值。
题目分析
“每头奶牛仅可以去往一台挤奶机,每台挤奶机最多有M头奶牛”这似乎是一个路径流量的问题,考虑使用网络流算法来解决。
那么,如何确定最长路径的最小值呢?可以先考虑简化问题,“给定一个最大距离L,能否分配这C头奶牛的挤奶机,使得每头奶牛到达挤奶机的距离都小于L”。
解决简化问题:虚拟一个源点和汇点。从源点引出C条容量分别为1的路径到达C头奶牛,再将K台机器分别引出一条容量为M的路径到达汇点。则问题转化为,构造C头奶牛到K台机器的网络路径,且从每头奶牛去往挤奶机的路径的容量为1,距离不超过L,使得网络从源点到汇点的最大流量为C,且C头奶牛走的路径的最大值最小。
然后,再通过二分法枚举最大距离L,找到最大距离的最小值。
具体实现的时候,使用Floyd算法求出奶牛到达挤奶机的最短路径长度;使用ISAP算法找出最大流;使用二分法确定最长的路径最小值。
实现(c++)
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX_NODE 235
#define MAX_EDGE_NUM 50000
#define INFINITE 1 << 20
#define min(a, b) a < b?a:b
struct Edge{
int from;
int to;
int w;
int next;
int rev;
bool operator==(const pair<int, int>& p){
return from == p.first && to == p.second;
}
}; Edge gEdges[MAX_EDGE_NUM];
int gFlow[MAX_NODE][MAX_NODE];
int gHead[MAX_NODE];
int gDist[MAX_NODE];
int gGap[MAX_NODE];
int gPre[MAX_NODE];
int gPath[MAX_NODE]; int gEdgeCount;
int gSource, gDestination;
void InsertEdge(int u, int v, int w){
Edge* it = find(gEdges, gEdges + gEdgeCount, pair<int, int>(u, v));
if (it != gEdges + gEdgeCount){
it->w = w;
}
else{
int e1 = gEdgeCount++;
gEdges[e1].from = u;
gEdges[e1].to = v;
gEdges[e1].w = w;
gEdges[e1].next = gHead[u];
gHead[u] = e1; int e2 = gEdgeCount++;
gEdges[e2].from = v;
gEdges[e2].to = u;
gEdges[e2].w = 0;
gEdges[e2].next = gHead[v];
gHead[v] = e2; gEdges[e1].rev = e2;
gEdges[e2].rev = e1;
}
gFlow[u][v] = w;
} void Bfs(){
memset(gGap, 0, sizeof(gGap));
memset(gDist, -1, sizeof(gDist));
gDist[gDestination] = 0;
gGap[0] = 1;
queue<int>Q;
Q.push(gDestination);
while (!Q.empty()){
int u = Q.front();
Q.pop();
for (int e = gHead[u]; e != -1; e = gEdges[e].next){
int v = gEdges[e].to;
if (gDist[v] >= 0)
continue;
gDist[v] = gDist[u] + 1;
gGap[gDist[v]] ++;
Q.push(v);
}
}
} int ISAP(int n){
int e, d, u = gSource;
int ans = 0;
Bfs();
while (gDist[gSource] <= n){
if (u == gDestination){
int min_flow = INFINITE;
for (e = gPath[u]; u != gSource; e = gPath[u = gPre[u]]){
min_flow = min(min_flow, gEdges[e].w);
}
u = gDestination;
for (e = gPath[u]; u != gSource; e = gPath[u = gPre[u]]){
gEdges[e].w -= min_flow;
gEdges[gEdges[e].rev].w += min_flow; gFlow[gPre[u]][u] -= min_flow;
gFlow[u][gPre[u]] += min_flow;
}
ans += min_flow;
}
for (e = gHead[u]; e != -1; e = gEdges[e].next){
if (gEdges[e].w > 0 && gDist[u] == gDist[gEdges[e].to] + 1)
break;
}
if (e >= 0){
gPre[gEdges[e].to] = u;
gPath[gEdges[e].to] = e;
u = gEdges[e].to;
}
else{
if (--gGap[gDist[u]] == 0)
break;
d = n;
for (int e = gHead[u]; e != -1; e = gEdges[e].next)
if (gEdges[e].w > 0)
d = min(d, gDist[gEdges[e].to]);
gDist[u] = d + 1;
++gGap[gDist[u]];
if (u != gSource)
u = gPre[u];
}
}
return ans;
} int gMinDist[MAX_NODE][MAX_NODE];
void Floyd(int n){
for (int k = 1; k <= n; k++){
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
if (gMinDist[i][j] > gMinDist[i][k] + gMinDist[k][j]){
gMinDist[i][j] = gMinDist[i][k] + gMinDist[k][j];
}
}
}
}
} void BuildGraph(int k, int c, int m, int max_dist){
memset(gHead, -1, sizeof(gHead));
gEdgeCount = 0;
gSource = 0;
gDestination = k + c + 1; for (int i = k + 1; i <= k + c; i++){
InsertEdge(gSource, i, 1);
}
for (int i = k + 1; i <= k + c; i++){
for (int j = 1; j <= k; j++){
if (gMinDist[i][j] <= max_dist)
InsertEdge(i, j, 1);
}
} for (int i = 1; i <= k; i++){
InsertEdge(i, gDestination, m);
}
}
void print_graph(int n){
for (int u = 0; u <= n; u++){
printf("node %d links to ", u);
for (int e = gHead[u]; e != -1; e = gEdges[e].next)
printf("%d(flow = %d) ", gEdges[e].to, gEdges[e].w);
printf("\n");
}
}
int main(){
int k, c, m, d;
while (scanf("%d %d %d", &k, &c, &m) != EOF){
for (int i = 1; i <= k + c; i++){
for (int j = 1; j <= k + c; j++){
scanf("%d", &gMinDist[i][j]);
if (i != j && gMinDist[i][j] == 0)
gMinDist[i][j] = INFINITE;
}
} Floyd(k + c);
int beg = 1, end = 40010;
while (beg < end){
int max_dist = (beg + end) / 2;
BuildGraph(k, c, m, max_dist);
// print_graph(k + c + 1);
int max_flow = ISAP(k + c + 2);
if (max_flow == c)
end = max_dist;
else
beg = max_dist + 1;
}
printf("%d\n", end);
}
return 0;
}
poj_2112 网络最大流+二分法的更多相关文章
- P3376 【模板】网络最大流
P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...
- HDU 3549 网络最大流再试
http://acm.hdu.edu.cn/showproblem.php?pid=3549 同样的网络最大流 T了好几次原因是用了cout,改成printf就A了 还有HDU oj的编译器也不支持以 ...
- 一般增广路方法求网络最大流(Ford-Fulkerson算法)
/* Time:2015-6-18 接触网络流好几天了 写的第一个模版————Ford-Fulkerson算法 作用:求解网络最大流 注意:源点是0 汇点是1 如果题目输入的是1到n 请预处理减1 * ...
- 算法模板——Dinic网络最大流 2
实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流 ...
- 算法模板——Dinic网络最大流 1
实现功能:同sap网络最大流 今天第一次学Dinic,感觉最大的特点就是——相当的白话,相当的容易懂,而且丝毫不影响复杂度,顶多也就是代码长个几行 主要原理就是每次用spfa以O(n)的时间复杂度预处 ...
- 图论算法-网络最大流【EK;Dinic】
图论算法-网络最大流模板[EK;Dinic] EK模板 每次找出增广后残量网络中的最小残量增加流量 const int inf=1e9; int n,m,s,t; struct node{int v, ...
- 网络最大流算法—EK算法
前言 EK算法是求网络最大流的最基础的算法,也是比较好理解的一种算法,利用它可以解决绝大多数最大流问题. 但是受到时间复杂度的限制,这种算法常常有TLE的风险 思想 还记得我们在介绍最大流的时候提到的 ...
- 洛谷 P3376 【【模板】网络最大流】
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行包含三个正整数ui. ...
- 洛谷P3376 【模板】网络最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
随机推荐
- 【Unity笔记】给UGUI元素添加交互性
如果想给UGUI元素添加交互性,如使一张图片能够被点击,具有normal.Highlighted.Pressed三态,可以给该物体添加组件Selectable. 已经具有交互性的物体不能再添加Sele ...
- C语言 · 新建Microsoft Word文档
算法提高 新建Microsoft Word文档 时间限制:1.0s 内存限制:256.0MB 问题描述 L正在出题,新建了一个word文档,想不好取什么名字,身旁一人惊问:“你出的题 ...
- SpringAOP来监控service层中每个方法的执行时间
使用AOP来说,太方便了,并且特别适合这类场景. 代码如下,这里是将要统计的信息写到log文件中,也可以设计成写入表中. package com.ecsoft.interceptor; import ...
- KafkaStream时间戳问题CreateTime = -1引起的程序中断
Exception in thread "app-8835188a-e0a0-46da-ac2a-6820ec197628-StreamThread-1" org.apache.k ...
- pku1204 Word Puzzles AC自动机 二维字符串矩阵8个方向找模式串的起点坐标以及方向 挺好的!
/** 题目:pku1204 Word Puzzles 链接:http://poj.org/problem?id=1204 题意:给定一个L C(C <= 1000, L <= 1000) ...
- TextBox控件的DataBindings属性
DataBindings属性是很多控件都有的属性,作用有2方面.一方面是用于与数据库的数据进行绑定,进行数据显示.另一方面用于与控件或类的对象进行数据绑定.这里主要关注后者.主要用法是将某个对象的某个 ...
- 使用JPedal取代PDFBox
http://wanggp.iteye.com/blog/1144177 ———————————————————————————————————————————————— 之前都是使用PDFBOX0. ...
- 关于Cocos2d-x节点和精灵节点的坐标、位置以及大小的设置
1.cocos2d-X中的坐标(0,0),就是运行框的左下角位置,所以运行框看起来就是一个第一象限. 2.节点的锚点就是我们setPosition所设定的位置,默认锚点是在节点的中心,也就是setPo ...
- Latex的各种帽子
\hat{A} \widehat{A} \tilde{A} \widetilde{A} \overline{A} \underline{A} \overbrace{A} \underbrace{A} ...
- 转载:Erlang 函数(Efficiency Guide)
转自:http://www.cnblogs.com/futuredo/archive/2012/10/26/2737644.html Functions 1 Pattern matching 模式匹 ...