首先floyd求最短路
然后构建网络流,其中源点到每一头牛容量为1,每一个挤奶器到汇点容量为m
牛到挤奶器容量为1.
二分答案,构建网络流。
// ShellDawn
// POJ2112
// No.22
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#define MM(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
using namespace std;
#define maxn 300
int n;
int D[maxn][maxn];
int E[maxn][maxn];
int V[maxn];
int P[maxn][maxn][2];
int C[maxn];
// 1~c牛,c+1~k+c挤奶器
void init(int gate,int k,int c,int m){
MM(E,0);
for(int i=1;i<=c;i++) E[0][i] = 1;
for(int i=c+1;i<=c+k;i++) E[i][n+1] = m;
for(int i=1;i<=c;i++){
for(int j=c+1;j<=c+k;j++){
if(D[i][j] <= gate){
E[i][j] = 1;
}
}
}
}
bool BFS(int s){
MM(V,0);MM(C,0);
queue<int> q;
q.push(s);
V[s] = 1;
while(!q.empty()){
int now = q.front();
q.pop();
for(int i=1;i<=n+1;i++){
if(V[i] == 0 && E[now][i] > 0){
q.push(i);
V[i] = V[now]+1;
int c = C[now];
P[now][c][0] = i;
P[now][c][1] = E[now][i];
C[now]++;
if(i == n+1) return true;
}
}
}
return false;
}
int DFS(int now,int minflow){
if(now == n+1) return minflow;
int flow = 0;
for(int i=0;i<C[now];i++){
int next = P[now][i][0];
int v = P[now][i][1];
int f = DFS(next,min(minflow,v));
flow += f;
minflow -= f;
E[now][next] -= f;
E[next][now] += f;
}
return flow;
}
int main(){
//freopen("A.txt","r",stdin);
int k,c,m;
cin>>k>>c>>m;
n = k + c;
MM(D,0x3f);
for(int i=c+1;i<=k+c;i++){
for(int j=c+1;j<=k+c;j++){
scanf("%d",&D[i][j]);
}
for(int j=1;j<=c;j++){
scanf("%d",&D[i][j]);
}
}
for(int i=1;i<=c;i++){
for(int j=c+1;j<=k+c;j++){
scanf("%d",&D[i][j]);
}
for(int j=1;j<=c;j++){
scanf("%d",&D[i][j]);
}
}
// floyd
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(D[i][j] == 0) D[i][j] = INF;
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
D[i][j] = min(D[i][j],D[i][k] + D[k][j]);
}
}
}
// binary search
int L = 0;
int R = 10001;
int ans = INF;
while(L<R){
int mid = (L+R)/2;
init(mid,k,c,m);
int flow = 0;
while(BFS(0)) flow+=DFS(0,INF);
if(flow == c){
ans = min(ans,mid);
R = mid;
}else L = mid + 1;
}
cout<<ans<<endl;
return 0;
}