题目大意:
有k个挤奶器,在牧场里有c头奶牛,每个挤奶器可以满足m个奶牛,奶牛和挤奶器都可以看成是实体,现在给出两个实体之间的距离,如果没有路径相连,则为0,现在问你在所有方案里面,这c头奶牛需要走的最大距离的最小值。
解题思路:
floyd+最大流+二分
首先用floyd求出两个实体间的最短距离,然后二分枚举最大距离的最小值,用最大流来判断是否存在这个解。
因为涉及Floyd所以INF设置的值最好不要太大。千万不能是0x7fffffff
二分枚举答案的时候,r可以设置初值为1e4即可。
在使用最大流判断是否存在解的时候,要对每个解都重新建图。
建图需要一个超级源点,把所有的奶牛与源点相连,容量设置为1
把所有的挤奶器与汇点相连,容量为m
然后对于挤奶器和奶牛的距离不超过判断的解的距离的连边,容量设置为1
然后求解即可。
(建图部分可以直接看代码比较好)
代码:
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
typedef struct node{
int v, cap, nxt;
node(int a = 0, int b = 0, int c = 0){
v = a; cap = b; nxt = c;
}
}Edge;
const int INF = 1e7;
const int maxn = 300;
const int maxm = 1e5;
Edge edge[maxm];
int t, tot, K, C, M, N;
int head[maxm], dis[maxn], d[maxn][maxn];
inline int Min(int a, int b){
return (a < b ? a : b);
}
void floyd(){
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]);
}
}
}
}
void add(int u, int v, int cap){
edge[tot] = Edge(v, cap, head[u]);
head[u] = tot++;
edge[tot] = Edge(u, 0, head[v]);
head[v] = tot++;
}
int bfs(){
queue<int> q;
while(!q.empty()) q.pop();
memset(dis, 0, sizeof(dis));
dis[0] = 1; q.push(0);
while(!q.empty()) {
int x = q.front(); q.pop();
if(x == t) break;
for(int i = head[x]; ~i; i = edge[i].nxt){
Edge &e = edge[i];
if(e.cap && dis[e.v] == 0){
dis[e.v] = dis[x] + 1;
q.push(e.v);
}
}
}
return dis[t];
}
int dfs(int x, int f){
if(x == t) return f;
int sum = 0;
for(int i = head[x]; ~i; i = edge[i].nxt){
Edge &e = edge[i];
if(e.cap && dis[e.v] == dis[x] + 1){
int ret = dfs(e.v, Min(e.cap, f));
sum += ret; f -= ret;
e.cap -= ret; edge[i^1].cap += ret;
}
}
return sum;
}
void buildGraph(int lev){
tot = 0;
memset(head, -1, sizeof(head));
for(int i = K + 1; i <= N; ++i) add(0, i, 1);
for(int i = 1; i <= K; ++i) add(i, t, M);
for(int i = K + 1; i <= N; ++i){
for(int j = 1; j <= K; ++j){
if(d[i][j] <= lev) add(i, j, 1);
}
}
}
bool dinic(){
int ret = 0;
while(bfs()) ret += dfs(0, INF);
return (ret >= C);
}
int main(){
while(~scanf("%d%d%d", &K, &C, &M)){
N = K + C; t = N + 1;
for(int i = 1; i <= N; ++i)
for(int j = 1; j <= N; ++j){
scanf("%d", &d[i][j]);
if(d[i][j] == 0) d[i][j] = INF;
}
floyd();
int l = 0, r = 1e4, ans, mid;
while(l < r){
mid = (l + r) >> 1;
buildGraph(mid);
if(dinic()) {
ans = mid; r = mid;
}else l = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}