floyd + 二分 + 最大流Dinic
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int MAX_K = 30;
const int MAX_C = 200;
const int MAX_M = 15;
const int MAX_V = 240;
const int INF = 10000000;
const int MAXVAL = 40000;
int K, M, C;
int d[MAX_V][MAX_V];
int V; // 顶点数 K + C
struct edge {int to, cap, rev; };
vector<edge> G[MAX_V];
int level[MAX_V];
int iter[MAX_V];
void add_edge(int from, int to, int cap) {
G[from].push_back((edge){to, cap, G[to].size()});
G[to].push_back((edge){from, 0, G[from].size() - 1});
}
void bfs(int s) {
memset(level, -1, sizeof(level));
queue<int> que;
level[s] = 0;
que.push(s);
while(!que.empty()) {
int v = que.front(); que.pop();
for (int i = 0; i < G[v].size(); i++) {
edge &e = G[v][i];
if(e.cap > 0 && level[e.to] < 0) {
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
}
int dfs(int v, int t, int f) {
if (v == t) return f;
for (int &i = iter[v]; i < G[v].size(); i++) {
edge &e = G[v][i];
if(level[v] < level[e.to] && e.cap > 0) {
int d = dfs(e.to, t, min(e.cap, f));
if(d > 0) {
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t) {
int flow = 0;
for (;;) {
bfs(s);
if (level[t] < 0) return flow;
memset(iter, 0, sizeof(iter));
int f;
while((f = dfs(s, t, INF)) > 0) {
flow += f;
}
}
}
void floyd() {
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
}
bool judge(int mid) {
//建图:0 ~ K-1 : K个机器
// K ~ K + C - 1 : C个奶牛
int s = K + C, t = s + 1;
for (int i = 0; i <= t; i++)
G[i].clear();
// 从s到奶牛,建流量为1的边
for (int i = 0; i < C; i++) {
add_edge(s, K + i, 1);
}
// 从奶牛机到t,建流量为M的边
for (int i = 0; i < K; i++) {
add_edge(i, t, M);
}
// 奶牛到奶牛机,若最短路小于等于mid,则建立一条流量为1的边
for (int i = 0; i < C; i++) {
for (int j = 0; j < K; j++) {
if(d[j][i + K] <= mid) {
add_edge(i + K, j, 1);
}
}
}
int ans = max_flow(s, t);
//cout << "mid = " << mid << " max_flow = " << ans << endl;
if (ans == C) {return true;}
else return false;
}
void solve() {
//先用floyd求出各实体间的最短路
V = K + C;
floyd();
//二分答案,用mid建图,若mid长度求出的流等于奶牛数,则mid可变短,否则mid需加长。
int lb = -1, ub = MAXVAL;
while(ub - lb > 1) {
int mid = (lb + ub) / 2;
if (judge(mid)) ub = mid;
else lb = mid;
}
printf("%d\n",ub);
}
int main() {
cin >> K >> C >> M;
for (int i = 0; i < K + C; i++) {
for (int j = 0; j < K + C; j++) {
scanf("%d", &d[i][j]);
if (i != j && d[i][j] == 0) {
d[i][j] = INF;
}
}
}
solve();
//system("pause");
}