这个题的意思是有K个挤奶机器, 和C个牛,一个机器每天最多服务W个奶牛, 如果将牛和机器看成顶点那么告诉两顶点之间的距离, 那么请最小化奶牛去挤奶的时候走的路的最大值, 首先我们可以使用floyd求出奶牛去某个挤奶机器的最短路径,然后二分一个答案, 建图, 我们再定义一个超级源点和超级汇点, 源点指向机器, 权值为W, 机器和奶牛之间也有边, 满足条件为边的长度小于等于二分的答案, 权值为1, 每个奶牛到汇点也有一个边权值为1, 求出此图的最大流观察其是否等于奶牛的数量, 代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; int K, C, M; int d[250][250]; const int maxn = 500; const int inf = 0x3f3f3f3f; struct Dinic { int n; //n个顶点 struct edge { int from, to, cap; }; vector<int> G[maxn]; vector<edge> e; int level[maxn], iter[maxn]; void init() { for(int i=0; i<=n; i++) G[i].clear(); e.clear(); } void add_edge(int u, int v, int cap) { e.push_back((edge) { u, v, cap }); e.push_back((edge) { v, u, 0 }); int m = e.size(); G[u].push_back(m-2); G[v].push_back(m-1); } void bfs(int s) { memset(level, -1, sizeof(level)); queue<int> que; level[s] = 0; que.push(s); while(!que.empty()) { int u = que.front(); que.pop(); for(int i=0; i<G[u].size(); i++) { edge &te = e[G[u][i]]; if(te.cap>0 && level[te.to]<0) { level[te.to] = level[u] + 1; que.push(te.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 &tpe = e[G[v][i]]; if(tpe.cap>0 && level[v]<level[tpe.to]) { int d = dfs(tpe.to, t, min(f, tpe.cap)); if(d > 0) { tpe.cap -= d; e[G[v][i]^1].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, 0x3fffffff)) > 0) flow += f; } } } di; void floyd() { int n = K+C; 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]); } bool check(int mid) { di.n = K+C+2; //0超级源点 machine 1-K cow K+1-K+C K+C+1超级汇点 di.init(); for(int i=1; i<=K; i++) //机器 { for(int j=1+K; j<=C+K; j++) if(d[i][j]<=mid) //奶牛 { int u=i, v=j; di.add_edge(u, v, 1); } di.add_edge(0, i, M); } for(int j=1; j<=C; j++) di.add_edge(K+j, K+C+1, 1); int f = di.max_flow(0, K+C+1); return f==C; } int main() { while(scanf("%d%d%d", &K, &C, &M)==3) { for(int i=1; i<=K+C; i++) for(int j=1; j<=K+C; j++) { scanf("%d", &d[i][j]); if(i!=j && d[i][j]==0) d[i][j] = inf; } floyd(); int l=0, r=100000; int ans; while(l <= r) { int mid = (l+r)/2; if(check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%d\n", ans); } return 0; }