POJ 2112 挤牛奶 floyd+最大流+二分
题意:
有k个挤奶器,c头牛..每个挤奶器和每头牛之间都有特定的距离..k个挤奶器的位置用1~k的编号表示..奶牛的位置用k+1~k+c表示
每个挤奶器每天最多为m头牛挤奶..
求安排每头牛到挤奶器前的最大距离的最小值..
思路:
先用floyd求出每头牛到每台挤奶器的最短距离..
然后用二分判断最大距离最小值是多少..
check()函数就是根据按距离建图后这个网络流的最大流==牛的头数
其中建图先建一个超级源点..作为每头牛的前驱..他们的流量为1..
然后建一个超级汇点..作为每台挤奶器的后继..他们的流量为m..
如果由floyd求出的最短距离 >= 二分假设的最大距离最小值x..就连线..然后根据这个求出的图来求最大流..
Tips:
※ 要注意全局变量和局部变量不要冲撞..
※ 求最大流算法很多..EK/Dicnic..还有..%&@^%$%
※ 这道题还可以用二分图的多重匹配来完成..<没做>
Code:
<EK>
1 #include <stdio.h> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 #define INF 0x1f1f1f1f 6 #define clr(x) memset(x, 0, sizeof(x)) 7 8 int G[250][250], K, c, m, n; 9 int arr[250][250]; 10 int dis[250][250]; 11 int flow[250][250], a[250], f, p[250]; 12 13 14 void init(int x) 15 { 16 int i, j, k; 17 clr(G); 18 for(i = 1; i <= K; ++i) 19 G[i][n+1] = m; 20 for(i = K+1; i <= n; ++i) 21 G[0][i] = 1; 22 23 for(i = K+1; i <= n; ++i) 24 for(j = 1; j <= K; ++j){ 25 if(arr[i][j] && arr[i][j] <= x) G[i][j] = 1; 26 } 27 } 28 29 int EK(int s, int t) 30 { 31 clr(flow); 32 clr(p); 33 queue<int> q; 34 int f = 0; 35 while(1) 36 { 37 clr(a); 38 a[s] = INF; 39 q.push(s); 40 while(!q.empty()) 41 { 42 int u = q.front(); 43 q.pop(); 44 for(int v = 0; v <= n+1; ++v) 45 if(!a[v] && G[u][v] > flow[u][v]) 46 { 47 p[v] = u; 48 q.push(v); 49 a[v] = a[u] < G[u][v] - flow[u][v]?a[u]:G[u][v]-flow[u][v]; 50 } 51 } 52 if(a[t] == 0) break; 53 for(int u = t; u != s; u = p[u]){ 54 flow[p[u]][u] += a[t]; 55 flow[u][p[u]] -= a[t]; 56 } 57 f += a[t]; 58 59 } 60 return f; 61 } 62 63 int main() 64 { 65 int i, j, k; 66 while(scanf("%d %d %d", &K, &c, &m) != EOF) 67 { 68 clr(arr); 69 n = K+c; 70 for(i = 1; i <= n; ++i) 71 for(j = 1; j <= n; ++j) 72 scanf("%d", &arr[i][j]); 73 74 for(k = 1; k <= n; ++k) 75 for(i = 1; i <= n; ++i){ 76 if(arr[i][k]) 77 for(j = 1; j <= n; ++j){ 78 if(arr[k][j] && (arr[i][k] + arr[k][j] < arr[i][j] || arr[i][j] == 0)) 79 arr[i][j] = arr[i][k]+arr[k][j]; 80 } 81 } 82 int low, top, mid; 83 low = top = 0; 84 for(i = K+1; i <= n; ++i) 85 for(j = 1; j <= K; ++j) 86 if(arr[i][j] > top) top = arr[i][j]; 87 88 int tmp; 89 while(low < top) 90 { 91 mid = (low+top)/2; 92 init(mid); 93 tmp = EK(0, n+1); 94 if(tmp != c) low = mid+1; 95 else top = mid; 96 } 97 printf("%d\n", low); 98 } 99 }
<Dicnic>
1 #include <stdio.h> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 #define INF 100000 6 #define MAX 300 7 8 int G[MAX][MAX]; 9 int map[MAX][MAX]; 10 bool sign[MAX][MAX]; 11 bool used[MAX]; 12 int K, c, n, m; 13 14 void bg(int x) 15 { 16 int i, j; 17 memset(map, 0, sizeof(map)); 18 19 for(i = K+1; i <= n; ++i) 20 map[0][i] = 1; 21 for(i = 1; i <= K; ++i) 22 map[i][n+1] = m; 23 24 for(i = K+1; i <= n; ++i) 25 for(j = 1; j <= K; ++j) 26 if(G[i][j] <= x) map[i][j] = 1; 27 } 28 29 bool bfs() 30 { 31 memset(used, 0, sizeof(used)); 32 memset(sign, 0, sizeof(sign)); 33 int queue[100*MAX] = {0}; 34 queue[0] = 0; 35 used[0] = 1; 36 int t = 1, f = 0; 37 while(f < t) 38 { 39 for(int i = 0; i <= n+1; ++i) 40 if(!used[i] && map[queue[f]][i]){ 41 queue[t++] = i; 42 used[i] = 1; 43 sign[queue[f]][i] = 1; 44 } 45 f++; 46 } 47 if(used[n+1]) return true; 48 else return false; 49 } 50 51 int dfs(int v, int sum) 52 { 53 int i, s, t; 54 if( v == n+1) return sum; 55 s = sum; 56 for(i = 0; i <= n+1; ++i){ 57 if(sign[v][i]){ 58 t = dfs(i, min(map[v][i], sum)); 59 map[v][i] -= t; 60 map[i][v] += t; 61 sum -= t; 62 } 63 } 64 return s-sum; 65 } 66 67 int main() 68 { 69 int i, j, k, l, r, mid, ans; 70 scanf("%d %d %d", &K, &c, &m); 71 n = K+c; 72 for(i = 1; i <= n; ++i) 73 for(j = 1; j <= n; ++j){ 74 scanf("%d", &G[i][j]); 75 if(G[i][j] == 0) G[i][j] = INF; 76 } 77 78 for(k = 1; k <= n; ++k) 79 for(i = 1; i <= n; ++i){ 80 if(G[i][k] != INF) 81 for(j = 1; j <= n; ++j) 82 G[i][j] = min(G[i][j], G[i][k]+G[k][j]); 83 } 84 85 l = 0, r = 10000; 86 while(l < r) 87 { 88 mid = (l+r)/2; 89 ans = 0; 90 bg(mid); 91 while(bfs()) ans += dfs(0, INF); 92 if(ans >= c) r = mid; 93 else l = mid+1; 94 } 95 printf("%d\n", r); 96 return 0; 97 }