poj 2112 Optimal Milking 最大流
题目大意:
有K个挤奶器,C头奶牛,每个挤奶器最多能给M头奶牛挤奶。
求使C头奶牛头奶牛需要走的路程的最大路程最小。
解题思路:
使用Floy预先求出任意两点间最短距离,然后二分枚举最大距离.
构图方案: 源点与奶牛连边,容量为1, 挤奶器与汇点连边,容量为M, 奶牛与挤奶器连边 (注意,这里只有单项边)
还要注意的是,因为预先求过最短路,初始化的时候对于0的边,赋值的无穷大不要设的太大,不然会溢出.
参考代码:
SAP(shortest augment path) 间隙优化, AC时间 110ms
View Code
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> using namespace std; const int inf = 10000000; const int MAXN = 500; #define MIN(a,b) (a)<(b)?(a):(b) #define MAX(a,b) (a)>(b)?(a):(b) int k, c, m, s, t, n, N; int mp[MAXN][MAXN]; int head[MAXN], idx, vh[MAXN], h[MAXN]; struct node{ int v, f, nxt; }edge[MAXN*MAXN]; void input() { n = k+c; s = 0; t = n+1; N = n+2; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) { scanf("%d", &mp[i][j] ); if( !mp[i][j] ) mp[i][j] = inf; } for(int z = 1; z <= n; z++) for(int i = 1; i <= n; i++) if( mp[i][z] != inf ) { for(int j = 1; j <= n; j++) if( mp[i][j] > mp[i][z]+mp[z][j] ) mp[i][j] = mp[i][z]+mp[z][j]; } } void AddEdge( int u, int v, int f ) { edge[idx].v = v; edge[idx].f = f; edge[idx].nxt = head[u]; head[u] = idx++; edge[idx].v = u; edge[idx].f = 0; edge[idx].nxt = head[v]; head[v] = idx++; } void build( int mid ) { memset( head, 0xff, sizeof(head) ); idx = 0; for(int i = 1; i <= k; i++) // 挤奶器 for(int j = k+1; j <= n; j++) //奶牛 { if( mp[j][i] <= mid ) // 这里注意,只有奶牛到挤奶器的边 AddEdge( j, i, 1 ); } for(int i = 1; i <= k; i++) //挤奶器与汇点连边 AddEdge( i, t, m ); for(int i = k+1; i <= n; i++) //奶牛与源点连边 AddEdge( s, i, 1 ); } int DFS(int u,int flow ) { if( u == t ) return flow; int tmp = h[u]+1, remain = flow; for(int i = head[u]; ~i; i = edge[i].nxt ) { int v = edge[i].v; if( edge[i].f && h[u] == h[v]+1 ) { int p = DFS( v, MIN( remain, edge[i].f )); edge[i].f -= p; edge[i^1].f += p; remain -= p; if( remain == 0 || h[s] == N ) return flow-remain; } } for(int i = head[u]; ~i; i = edge[i].nxt ) if( edge[i].f ) tmp = MIN( tmp, h[ edge[i].v ] ); if( !( --vh[ h[u] ] ) ) h[s] = N; else ++vh[ h[u] = tmp+1 ]; return flow-remain; } int sap() { int maxflow = 0; memset( h, 0, sizeof(h)); memset( vh, 0, sizeof(vh)); vh[0] = N; while( h[s] < N ) maxflow += DFS( s, inf ); return maxflow; } void solve() { int l = 0, r = 100000; while( r > l ) { int mid = (l+r)>>1; build( mid ); if( sap() >= c ) r = mid; else l = mid+1; } printf("%d\n", r ); } int main() { while( scanf("%d%d%d", &k,&c,&m ) != EOF) { input(); solve(); } return 0; }