![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
//poj 2112 Optimal Milking // floyd + 二分 + 最大流 //题意:第一行给出K,C,M。 //分别表示挤奶机台数K,奶牛数C,没台挤奶机一天能处理的奶牛数 //接下去是(K+C) * (K+C) 的矩阵,表示各个点之间的距离 //0表示不能到达。奶牛走到机器挤奶,求每头牛都要被处理所走的路最少的情况下, //每头牛到机器距离中最长的边是多少。记得每台机器都有限制奶牛数 //思路: //先用floyd 求出各个点之间的最小路,找出所有路径中最短和最长的边 //对最长路径进行二分,后建立source连接奶牛,容量为1; //建sink,让机器连向sink,容量为机器一天所能处理奶牛的数量; //奶牛向机器连边,容量为INF //注意: //奶牛和机器之间的边可以多次使用 //建的图是有向图,只能从奶牛指向机器有容量INF,机器指向奶牛容量为0 //2 2 1 //0 0 1 3 //0 0 2 100 //1 2 0 0 //3 100 0 0 #define infile freopen("in.txt", "r", stdin); #include <stdio.h> #include <string.h> #include <queue> using namespace std; const int INF = 1<<30; const int N = 255; int n, n_mach, n_cow, per_flow, eid; int map[N][N], head[N], level[N]; struct EDGE { int ed, next, cap; }edge[2*N*N]; void floyd() //floyd求各个点之间的最短路 { for(int k = 1; k <= n; ++k) { for(int i = 1; i <= n; ++i) { if(i != k) { for(int j = 1; j <= n; ++j) { if(j != k && j != i) { if(map[i][j]-map[i][k] > map[k][j]) { map[i][j] = map[i][k] + map[k][j]; } } } } } } } void add_edge(int st, int ed, int cap) { edge[eid].ed = ed, edge[eid].cap = cap; edge[eid].next = head[st], head[st] = eid++; edge[eid].ed = st, edge[eid].cap = 0; //只能从牛到机器,是有向边 edge[eid].next = head[ed], head[ed] = eid++; } bool bfs() { memset(level, -1, sizeof(level)); queue<int>que; que.push(0); level[0] = 1; while(!que.empty()) { int now = que.front(); que.pop(); for(int i = head[now]; i != -1; i = edge[i].next) { int ed = edge[i].ed; if(edge[i].cap > 0 && level[ed] == -1) { level[ed] = level[now] + 1; que.push(ed); } } } if(level[n+1] == -1) return false; return true; } int dfs(int now, int flow) { if(now == n+1) return flow; int tmp = 0; //tmp为从now流出去的流量 for(int i = head[now]; i != -1; i = edge[i].next) { int m = min(edge[i].cap, flow - tmp); int ed = edge[i].ed, f; if(edge[i].cap > 0 && level[now]+1 == level[ed] && flow > tmp && (f = dfs(ed, m))) { edge[i].cap -= f; edge[i^1].cap += f; tmp += f; } } if(tmp == 0) level[now] = -1; return tmp; } int dinic() { int flow = 0; while(bfs()) flow += dfs(0, INF); return flow; } void binarySearch() { int high = 0, low = INF; for(int i = 1; i <= n; ++i) { for(int j = i+1; j <= n; ++j) { low = map[i][j] < low ? map[i][j] : low; if(map[i][j] != INF) high = map[i][j] > high ? map[i][j] : high; } } while(low < high) { eid = 0; memset(head, -1, sizeof(head)); int mid = low + (high-low)/2; for(int i = n_mach+1; i <= n; ++i) { add_edge(0, i, 1); //source为0,连到每头牛,容量为1 for(int j = 1; j <= n_mach; ++j) { //注意:这里只能从奶牛走向机器,是单向边 if(map[i][j] <= mid) { //这里奶牛到机器的容量是INF,表示奶牛和机器之间的边可以用不止一次 add_edge(i, j, INF); // printf("%d->%d\n", i, j); } } } for(int i = 1; i <= n_mach; ++i)//sink为n+1,每台机器连向sink, add_edge(i, n+1, per_flow); //容量为每台机器一天所能处理的奶牛数 int flow = dinic(); if(flow < n_cow) low = mid + 1; else high = mid; } printf("%d\n", low); } int main() { //infile while(scanf("%d%d%d", &n_mach, &n_cow, &per_flow) != EOF) { n = n_mach + n_cow; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= n; ++j) { scanf("%d", &map[i][j]); map[i][j] = map[i][j] == 0 ? INF : map[i][j]; } } floyd(); binarySearch(); } return 0; }