【题意】:给出k个机器,c只牛,每台机器一天最多可以服务m只牛,再给出(k+c)*(k+c)的矩阵,代表每两个实体(牛和牛,牛和机器,机器和机器)之间的直接距离。
              问:使全部牛都有机器服务时,牛走的最长路最短是多少?

【题解】:显然这是一个最大值最小化的问题。我们很容易就想到二分枚举答案判断可行性。
              首先floyd预处理每对点之间的最短距离,这样我们可以保证牛每次都走最短路到达机器。
              之后开始枚举距离(设当前枚举的距离为limit),遍历每个牛与每个机器的最短路,如果maz[i][j] <= limit 我们就连边i->j,表示牛i可以到达机器j,容量为1(inf)。
              加入一个源点s,向每个牛连边,容量为1,代表每个牛只能被一个机器服务。
              加入一个汇点t,向每个机器连反向边,容量为m,代表每个机器最多可以服务m只牛。
              最后跑最大流,如果最大流等于c,表示limit可以满足条件,更新ans就可以了。

【代码】:
  1 #include "iostream"
  2 #include "cstdio"
  3 #include "cstring"
  4 #include "algorithm"
  5 using namespace std;
  6 #define maxn 500
  7 #define maxm 50005
  8 const int INF = 999999999;
  9 int k, c, m, n;
 10 
 11 struct Edge {
 12     int u, v, cap, flow, next;
 13 }et[maxm];
 14 int maz[maxn][maxn], ans[maxn * maxn];
 15 int s, t, tot, tot1, eh[maxn], cur[maxn], pre[maxn], dist[maxn], low[maxn], cnt[maxn];
 16 
 17 void add(int u, int v, int cap, int flow) {
 18     Edge e = {u, v, cap, flow, eh[u]};
 19     et[tot] = e;
 20     eh[u] = tot++;
 21 }
 22 
 23 void addedge(int u, int v, int cap) {
 24     add(u, v, cap, 0), add(v, u, 00);
 25 }
 26 
 27 void init() {
 28     tot = 0;
 29     memset(eh, -1sizeof(eh));
 30 }
 31 
 32 bool isap(int s, int t, int n) {
 33     int u, v, now;
 34     memset(dist, 0sizeof(dist));
 35     memset(low, 0sizeof(low));
 36     for(u = 0; u <= n; u++) cur[u] = eh[u];
 37     int flow = 0;
 38     u = s;
 39     low[s] = INF, cnt[0= n;
 40     while(dist[s] < n) {
 41         for(now = cur[u]; now != -1; now = et[now].next)
 42             if(et[now].cap - et[now].flow && dist[u] == dist[v = et[now].v] + 1break;
 43         if(now != -1) {
 44             cur[u] = pre[v] = now;
 45             low[v] = min(low[u], et[now].cap - et[now].flow);
 46             u = v;
 47             if(u == t) {
 48                 for(; u != s; u = et[pre[u]].u) {
 49                     et[pre[u]].flow += low[t];
 50                     et[pre[u]^1].flow -= low[t];
 51                 }
 52                 flow += low[t], low[s] = INF;
 53             }
 54         } else {
 55             if(--cnt[dist[u]] == 0break;
 56             dist[u] = n;
 57             cur[u] = eh[u];
 58             for(now = eh[u]; now != -1; now = et[now].next)
 59                 if(et[now].cap - et[now].flow && dist[u] > dist[et[now].v] + 1
 60                     dist[u] = dist[et[now].v] + 1;
 61             cnt[dist[u]]++;
 62             if(u != s) u = et[pre[u]].u;
 63         }
 64     }
 65     return flow == c;
 66 }
 67 
 68 void floyd() {
 69     for(int l = 1; l <= n; l++) {
 70         for(int i = 1; i <= n; i++)
 71             if(maz[i][l])
 72             for(int j = 1; j <= n; j++
 73                 if(maz[l][j] && i != j) {
 74                     if(maz[i][j] == 0) maz[i][j] = maz[i][l] + maz[l][j];
 75                     else maz[i][j] = min(maz[i][j], maz[i][l] + maz[l][j]);
 76                 }
 77     }
 78     tot1 = 0;
 79     for(int i = 1; i <= n; i++
 80         for(int j = i + 1; j <= n; j++)
 81             ans[tot1++= maz[i][j];
 82     sort(ans, ans + tot1);
 83 }
 84 
 85 void build(int limit) {
 86     init();
 87     for(int i = 1; i <= c; i++
 88         addedge(s, k + i, 1);
 89     for(int i = 1; i <= k; i++) {
 90         addedge(i, t, m);
 91         for(int j = 1; j <= c; j++) {
 92             if(maz[i][k + j] <= limit && maz[i][k + j])
 93                 addedge(k + j, i, 1);
 94         }
 95     }
 96 }
 97     
 98 int solve() {
 99     int l = 0, r = tot1 - 1, res = -1;
100     while(l <= r) {
101         int mid = (l + r) >> 1;
102         build(ans[mid]);
103         if(isap(s, t, t - s + 1)) res = ans[mid], r = mid - 1;
104         else l = mid + 1;
105     }
106     return res;
107 }
108 
109 int main() {
110     cin >> k >> c >> m;
111     s = 0, t = k + c + 1;
112     n = k + c;
113     for(int i = 1; i <= n; i++
114         for(int j = 1; j <= n; j++)
115             cin >> maz[i][j];
116     floyd();
117     cout << solve() << endl;
118     return 0;
119 }