【最大流+floyd+二分+dinic】北大 poj 2112 Optimal Milking

来源:互联网 发布:淘宝香水时代真假 编辑:程序博客网 时间:2024/05/16 18:06


/* THE PROGRAM IS MADE BY PYY *//*----------------------------------------------------------------------------//    Copyright (c) 2012 panyanyany All rights reserved.    URL   : http://poj.org/problem?id=2112    Name  : 2112 Optimal Milking    Date  : Friday, February 10, 2012    Time Stage : 4 hours    Result:                                                                                  9791440panyanyany2112Accepted592K172MSC++4274B2012-02-10 15:28:44Test Data :2 3 20 3 2 1 13 0 3 2 02 3 0 1 01 2 1 0 21 0 0 2 01 1 10 11 0  2 2 10 0 1 30 0 2 1001 2 0 03 100 0 0Review :犯了一些概念性的错误,太失败了……//----------------------------------------------------------------------------*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#define MEM(a, v)memset (a, v, sizeof (a))// a for address, v for value#define max(x, y)((x) > (y) ? (x) : (y))#define min(x, y)((x) < (y) ? (x) : (y))#define INF(0x3f3f3f3f)#define MAXN(234)#define DB/##/intK, C, M, n, low, hig ;intmap[MAXN][MAXN], net[MAXN][MAXN], level[MAXN], q[MAXN] ;void floyd(){int i, j, k ;for (k = 1 ; k <= n ; ++k)for (i = 1 ; i <= n ; ++i)for (j = i+1 ; j <= n ; ++j){map[j][i] = map[i][j] = min(map[i][j], map[i][k]+map[k][j]) ;}}int dinic (const int beg, const int end){int sum, i, u, v, head, tail ;sum = 0 ;while (true){head = tail = 0 ;q[tail++] = beg ;MEM (level, -1) ;level[beg] = 0 ;while (head < tail){u = q[head++] ;for (i = beg ; i <= end ; ++i)if (net[u][i] > 0 && level[i] == -1){level[i] = level[u] + 1 ;if (end == i){head = tail ;break ;}q[tail++] = i ;}}if (-1 == level[end])break ;tail = 0 ;q[tail++] = beg ;u = beg ;while (1){if (end == u){int flow = INF, qbreak ;for (i = 1 ; i < tail ; ++i){u = q[i-1] ;v = q[i] ;if (flow >= net[u][v]){flow = net[u][v] ;qbreak = i - 1 ;}}sum += flow ;for (i = 1 ; i < tail ; ++i){u = q[i-1] ;v = q[i] ;net[u][v] -= flow ;net[v][u] += flow ;}u = q[qbreak] ;tail = qbreak + 1 ;}for (i = beg ; i <= end ; ++i)if (net[u][i] > 0 && level[u]+1 == level[i])break ;if (i > end){if (tail-1 == 0)break ;level[q[--tail]] = -1 ;u =q[tail-1] ;}else{q[tail++] = i ;u = i ;}}}return sum ;}void makegraph(const int lim){int i, j ;MEM(net, 0) ;for (i = 1 ; i <= K ; ++i)// 错误代码:for (j = 1 ; j <= n ; ++j)// 错误代码: for (j = i+1 ; j <= n ; ++j)// 首先,流向必须是单向的,map[u][v] 若有流量,则map[v][u]的流量须为0// 其次,必须是由挤奶机流向奶牛,或者从奶牛流向挤奶机。for (j = K+1 ; j <= n ; ++j)net[i][j] = (map[i][j] <= lim) ;//? INF : 0 ;// 源点到所有挤奶机的流量为 Mfor (i = 1 ; i <= K ; ++i)net[0][i] = M ;// 所有奶牛到汇点的流量为 1for (i = K+1 ; i <= n ; ++i)net[i][n+1] = 1 ;}int main(){int i, j ;int ans, tmpans ;while (scanf ("%d%d%d", &K, &C, &M) != EOF){MEM (net, 0) ;MEM (map, 0) ;n = K+C ;for (i = 1 ; i <= n ; ++i)for (j = 1 ; j <= n ; ++j){scanf("%d", &map[i][j]) ;if (0 == map[i][j])map[i][j] = INF ;}// 求任意两点间最短路,为二分高度做准备floyd() ;for (i = 1 ; i <= K ; ++i)net[0][i] = M ;for (i = K+1 ; i <= n ; ++i)net[i][n+1] = 1 ;ans = INF ;// 保险起见,先初始化一下int mid ;// 本来是在 floyd 里面对每条路径进行比较的,然后可以缩小[low,hig]的区间// 但是这样代码量大了,比较不容易维护,所以在后来查错的时间就挪出来,// 直接赋值了low = 0 ;hig = INF ;while (low <= hig){mid = (low + hig) / 2 ;// 每次限定改变了,就要重新制一次图// 本来是可以在 dinic 里面增加一些代码,在制层次图和增广路的时候对// 路径检查距离,从而限定它们的距离的。比如:// if (map[u][i] <= mid && net[u][i] > 0 && level[i] == -1)// 但是这样一来,相当于给本来完好的代码埋下了未知的地雷。// 如果哪里漏了对 map[u][i]<=mid 的判断的话,就很难查错了makegraph(mid) ;tmpans = dinic (0, n+1) ;if (tmpans == C){ans = mid ;// 一开始会习惯性地写成 ans = tmpans 。hig = mid - 1 ;}elselow = mid + 1 ;}printf ("%d\n", ans) ;}return 0 ;}


原创粉丝点击