POJ 2112 Optimal Milking (二分 + 最大流)

题目大意:

在一个农场里面,有k个挤奶机,编号分别是 1..k,有c头奶牛,编号分别是k+1 .. k+c,每个挤奶机一天最让可以挤m头奶牛的奶,奶牛和挤奶机之间用邻接矩阵给出距离。求让所有奶牛都挤到

奶的情况下,走的最远的那头奶牛走的距离最小是多少。

数据保证有解。

算法讨论:

首先可以想到是二分,然后在选择流网络的时候,一开始选择的最小费用最大流,让二分的边权充当最小费用,但是这样跑发现每次二分的是我们要跑的答案,不可行。所以就改用最大流。

最大流肯定是在二分的情况下判定最大流是否等于c,即是否所有的奶牛都可以挤到奶,所以一开始我的做法是直接把所有的边都加进去,然后在跑bfs的时候把边权大于二分值的边卡掉,但是发现这样是不可行的,(至于为什么不可行,有待思考。。。。)然后另一种做法就是每一次二分的时候都是重新加边(当前是小于二分值的边),然后跑最大流。但是不知道为什么我跑出来那么的效率低下。加边就是这样加:从超级源点向每头牛加流量为1的边,每头牛向距离小于二分当前值的挤奶机加流量为1的边,每个挤奶机向超级汇点加流量为m的边,根据入流等于出流的原理,这样就可以保证每个挤奶机至多只挤m头牛的奶了。

Codes:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 
  8 using namespace std;
  9 
 10 int k, c, mm, l, r, Mid;
 11 int arr[250][250];
 12 
 13 struct MF{
 14     static const int N = 230 + 5;
 15     static const int M = 300 * 300 + 5;
 16     static const int oo = 0x3f3f3f3f;
 17     
 18     int n, m, s, t, tot;
 19     int first[N], next[M];
 20     int u[M], v[M], cap[M], flow[M];
 21     int dis[N], cur[N];
 22     bool vi[M];
 23     
 24     void Clear(){
 25         tot = 0;
 26         memset(first, -1, sizeof first);
 27         memset(flow, 0 ,sizeof flow);
 28     }
 29     void Add(int from, int to, int cp, int flw){
 30         u[tot] = from; v[tot] = to; cap[tot] = cp; flow[tot] = flw;
 31         next[tot] = first[u[tot]];
 32         first[u[tot]] = tot;
 33         ++ tot;
 34     }
 35     bool bfs(){
 36         memset(vi, false, sizeof vi);
 37 
 38         queue <int> q;
 39         dis[s] = 0;vi[s] = true;
 40         q.push(s);
 41         
 42         while(!q.empty()){
 43             int now = q.front();q.pop();
 44             for(int i = first[now]; i != -1; i = next[i]){
 45                 if(!vi[v[i]] && cap[i] > flow[i]){
 46                     vi[v[i]] = true;
 47                     dis[v[i]] = dis[now] + 1;
 48                     q.push(v[i]);
 49                 }
 50             }
 51         }
 52         return vi[t];
 53     }    
 54     int dfs(int x, int a){
 55         if(x == t || a == 0) return a;
 56         int flw = 0, f;
 57         int &i = cur[x];
 58         for(i = first[x]; i != -1; i = next[i]){
 59             if(dis[x] + 1 == dis[v[i]] && (f = dfs(v[i], min(a, cap[i]-flow[i]))) > 0){
 60                 flow[i] += f; flow[i^1] -= f;
 61                 a -= f; flw += f;
 62                 if(a == 0) break;
 63             }
 64         }
 65         return flw;
 66     }
 67     int MaxFlow(int s, int t){
 68         this->s = s;this->t = t;
 69         int flw = 0;
 70         while(bfs()){
 71             memset(cur, 0, sizeof cur);
 72             flw += dfs(s, oo);
 73         }
 74         return flw;
 75     }
 76 }Net;
 77 
 78 void Floyed(){
 79     for(int kk = 1; kk <= k + c; ++ kk)
 80         for(int i = 1; i <= k + c; ++ i)
 81             for(int j = 1; j <= k + c; ++ j)
 82                 if(kk != i && i != j && kk != j)
 83                     if(arr[i][kk] < 1000000 && arr[kk][j] < 1000000)
 84                         arr[i][j] = min(arr[i][j], arr[i][kk] + arr[kk][j]);
 85 }
 86 
 87 bool check(){
 88     Net.Clear();
 89     for(int i = 1; i <= c; ++ i){
 90         Net.Add(0, i + k, 1, 0);
 91         Net.Add(i + k, 0, 0, 0);
 92     }
 93     for(int i = 1; i <= k; ++ i){
 94         Net.Add(i, Net.n + 1, mm, 0);
 95         Net.Add(Net.n + 1, i, 0, 0);
 96     }
 97     for(int i = k + 1; i <= k + c; ++ i){
 98         for(int j = 1; j <= k; ++ j){
 99             if(arr[i][j] <= Mid){
100                 Net.Add(i, j, 1, 0);
101                 Net.Add(j, i, 0, 0);
102             }
103         }
104     }
105     if(Net.MaxFlow(0, Net.n + 1) == c) return true;
106     return false;
107 }
108 
109 void Solve(){
110     int ans=0;l = 1;r = 10000;
111     while(l <= r){
112         Mid = l + (r - l) / 2;
113         if(check()){
114             ans = Mid;r = Mid - 1;
115         }
116         else l = Mid + 1;
117     }
118     printf("%d
", ans);
119 }
120 int main(){
121 
122     scanf("%d%d%d", &k, &c, &mm);
123     Net.n = k + c;
124     memset(arr, 127/3, sizeof arr);
125     for(int i = 1; i <= k + c; ++ i)
126         for(int j = 1; j <= k + c; ++ j){
127             scanf("%d", &arr[i][j]);
128             arr[i][j] = arr[i][j] == 0 ? Net.oo : arr[i][j];
129         }
130     Floyed();
131     Solve();
132     return 0;
133 }
POJ 2112
原文地址:https://www.cnblogs.com/sxprovence/p/5108022.html