POJ 2112 - Optimal Milking

原题地址:http://poj.org/problem?id=2112

题目大意:有K个挤奶机(标号为1 ~ K)和C头奶牛(编号为K + 1 ~ K + C),以邻接矩阵的方式给出它们两两之间的距离,每个挤奶机最多能挤M头奶牛的奶,求一种紧挨方案使得所有挤奶机到奶牛的距离的最大值最小

数据范围和一些细节:1 <= K <= 30, 1 <= C <= 200, 1 <= M <= 15, 每条边的长度L 满足 1 <= L <= 200。两点之间如果没有直接连接的边,则在邻接矩阵中给出"0"。邻接矩阵的一行可能会断成多行

题目分析:

这道题和昨天那道2455大同小异,都是使路径长最大值最小。不同的是,2455那道题要求的是路径上的某一条最长边的长度最小,而这道题是满足两点之间的路径长的最大值最小。所以这道题先用Floyd算法预处理出每对顶点之间的最短路,然后二分答案k,将距离小于k的两点之间连容量为1的边,反向边容量为0(注意,在这里连边的时候只能连接挤奶机和奶牛,不能连其它边,我在这里WA了几次)。最后新建源点和汇点,从源点向每台挤奶机连接容量为M的边,从每头奶牛向汇点连接容量为1的边,判断最大流是否等于C。

  1 //date 20140119

  2 #include <cstdio>

  3 #include <cstring>

  4 

  5 const int maxn = 250;

  6 const int maxm = 110000;

  7 const int INF = 99999999;

  8 

  9 inline int getint()

 10 {

 11     int ans(0); char w = getchar();

 12     while('0' > w || w > '9')w = getchar();

 13     while('0' <= w && w <= '9')

 14     {

 15         ans = ans * 10 + w - '0';

 16         w = getchar();

 17     }

 18     return ans;

 19 }

 20 

 21 inline int min(int a, int b){return a < b ? a : b;}

 22 inline int max(int a, int b){return a > b ? a : b;}

 23 

 24 int K, C, M;

 25 int n;

 26 int map[maxn][maxn];

 27 

 28 struct edge

 29 {

 30     int v, c, next;

 31 }E[maxm];

 32 int s, t;

 33 int a[maxn], now[maxn];

 34 int lab[maxn];

 35 int nedge;

 36 

 37 inline void add(int u, int v, int c)

 38 {

 39     E[++nedge].v = v;

 40     E[nedge].c = c;

 41     E[nedge].next = a[u];

 42     a[u] = nedge;

 43 }

 44 

 45 inline void floyd()

 46 {

 47     for(int k = 1; k <= n; ++k)

 48         for(int i = 1; i <= n; ++i)

 49             for(int j = 1; j <= n; ++j)

 50             {

 51                 if(i == k || j == k || i == j)continue;

 52                 map[i][j] = min(map[i][j], map[i][k] + map[j][k]);

 53             }

 54 }

 55 

 56 inline int label()

 57 {

 58     static int q[maxn];

 59     int l = 0, r = 1;

 60     memset(lab, 0xFF, sizeof lab);

 61     q[1] = s; lab[s] = 0;

 62     while(l < r)

 63     {

 64         int x = q[++l];

 65         for(int i = a[x]; i; i = E[i].next)

 66             if(E[i].c > 0 && lab[E[i].v] == -1)

 67             {

 68                 lab[E[i].v] = lab[x] + 1;

 69                 q[++r] = E[i].v;

 70             }

 71     }

 72     return lab[t] != -1;

 73 }

 74 

 75 int Dinic(int v, int f)

 76 {

 77     if(v == t)return f;

 78     int res = 0, w;

 79     for(int i = now[v]; i; now[v] = i = E[i].next)

 80         if((f > 0) && (E[i].c > 0) && (lab[E[i].v] == lab[v] + 1) && (w = Dinic(E[i].v, min(E[i].c, f))))

 81         {

 82             E[i].c -= w;

 83             E[i ^ 1].c += w;

 84             res += w;

 85             f -= w;

 86             if(f == 0)break;

 87         }

 88     return res;

 89 }

 90 

 91 inline int max_flow()

 92 {

 93     int ans = 0;

 94     while(label())

 95     {

 96         for(int i = 1; i <= t; ++i)now[i] = a[i];

 97         ans += Dinic(s, INF);

 98     }

 99     return ans;

100 }

101 

102 inline bool check(int mid)

103 {

104     memset(a, 0, sizeof a);

105     nedge = 1;

106     for(int i = 1; i <= K; ++i)

107         for(int j = K + 1; j <= n; ++j)

108             if(map[i][j] <= mid){add(i, j, 1); add(j, i, 0);}

109     

110     for(int i = 1; i <= K; ++i){add(s, i, M); add(i, s, 0);}

111     for(int i = 1; i <= C; ++i){add(i + K, t, 1); add(t, i + K, 0);}

112     return (max_flow() == C) ;

113 }

114 

115 inline int solve(int l, int r)

116 {

117     int mid;

118     while(l < r)

119     {

120         mid = (l + r) >> 1;

121         if(check(mid))r = mid;

122         else l = mid + 1;

123     }

124     return l;

125 }

126 

127 int main()

128 {

129     K = getint(); C = getint(); M = getint();

130     n = K + C; s = n + 1; t = n + 2;

131     int minl = INF, maxl = 0;

132     for(int i = 1; i <= n; ++i)

133         for(int j = 1; j <= n; ++j)

134         {

135             map[i][j] = getint();

136             if(map[i][j] == 0)map[i][j] = INF;

137         }

138     floyd();

139     for(int i = 1; i <= K; ++i)

140         for(int j = K + 1; j <= n; ++j)

141         {

142             if(map[i][j] == INF)continue;

143             minl = min(minl, map[i][j]);

144             maxl = max(maxl, map[i][j]);

145         }

146     int ans = solve(minl, maxl);

147     printf("%d\n", ans);

148     return 0;

149 }

一直想写SGU187一直也没写过……求各位指点

你可能感兴趣的:(poj)