/* 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: 9791440 panyanyany
2112
Accepted 592K 172MS C++
4274B 2012-02-10 15:28:44
Test Data :
2 3 2
0 3 2 1 1
3 0 3 2 0
2 3 0 1 0
1 2 1 0 2
1 0 0 2 0
1 1 1
0 1
1 0
2 2 1
0 0 1 3
0 0 2 100
1 2 0 0
3 100 0 0
Review :
犯了一些概念性的错误,太失败了……
//----------------------------------------------------------------------------*/
#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 /##/
int K, C, M, n, low, hig ;
int map[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 ;
// 源点到所有挤奶机的流量为 M
for (i = 1 ; i <= K ; ++i)
net[0][i] = M ;
// 所有奶牛到汇点的流量为 1
for (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 ;
}
else
low = mid + 1 ;
}
printf ("%d\n", ans) ;
}
return 0 ;
}