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\n", 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

时间: 2024-10-06 00:23:03

POJ 2112 Optimal Milking (二分 + 最大流)的相关文章

POJ 2112 Optimal Milking 二分答案+最大流

首先二分最长的边,然后删去所有比当前枚举的值长的边,算最大流,看是否能满足所有的牛都能找到挤奶的地方 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include

POJ 2112 —— Optimal Milking 二分+Floyd+最大流

原题:http://poj.org/problem?id=2112 #include<cstdio> #include<cstring> #include<string> #include<queue> #include<vector> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; const int maxn = 250; int dis[maxn][

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

<题目链接> 题目大意: 有K台挤奶机和C头奶牛,都被视为物体,这K+C个物体之间存在路径.给出一个 (K+C)x(K+C) 的矩阵A,A[i][j]表示物体i和物体j之间的距离,有些物体之间可能没有直接通路. 每台挤奶机可以容纳m头奶牛去挤奶,且每个奶牛仅可以去往一台挤奶机.现在安排这C头奶牛去挤奶,每头奶牛会去往某个挤奶机,求出这C头奶牛去其挤奶的最长路径的最小值. 解题分析: 因为要求最长路径的最小值,所以我们很容易想到二分答案.由于数据量较小,所以我们先用floyed求出所有点之间的最

POJ 2112 Optimal Milking(最大流)

题目链接:http://poj.org/problem?id=2112 Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) cows. A set of paths of various lengths runs among the cows and the milking machines. The

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

POJ 2112 Optimal Milking 题目链接 题意:给定一些机器和奶牛,在给定距离矩阵,(不在对角线上为0的值代表不可达),每个机器能容纳m个奶牛,问所有奶牛都能挤上奶,那么走的距离最大的奶牛的最小值是多少 思路:明显的二分+最大流,注意floyd求出的距离矩阵最大值可能不止200,所以二分的上限要注意 代码: #include <cstdio> #include <cstring> #include <queue> #include <algori

POJ 2112 Optimal Milking 最优挤奶方案 Floyd算法+二分查找+最大流

题目链接:POJ 2112 Optimal Milking Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 12446   Accepted: 4494 Case Time Limit: 1000MS Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among

POJ 2112 Optimal Milking (二分 + floyd + 网络流)

POJ 2112 Optimal Milking 链接:http://poj.org/problem?id=2112 题意:农场主John 将他的K(1≤K≤30)个挤奶器运到牧场,在那里有C(1≤C≤200)头奶牛,在奶牛和挤奶器之间有一组不同长度的路.K个挤奶器的位置用1-K的编号标明,奶牛的位置用K+1-K+C 的编号标明.每台挤奶器每天最多能为M(1≤M≤15)头奶牛挤奶.寻找一个方案,安排每头奶牛到某个挤奶器挤奶,并使得C 头奶牛需要走的所有路程中的最大路程最小.每个测试数据中至少有一

POJ 2112—— Optimal Milking——————【多重匹配、二分枚举答案、floyd预处理】

Optimal Milking Time Limit:2000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2112 Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 20

POJ 2112 Optimal Milking

Optimal Milking Time Limit: 2000ms Memory Limit: 30000KB This problem will be judged on PKU. Original ID: 211264-bit integer IO format: %lld      Java class name: Main FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures amon