题意: 有K个挤奶器,和C头牛,让你求所有牛到挤奶器的最近距离的最远是多大。
题解: 由于挤奶器的不唯一,所以我们不能直接的求,然后对于多源点的求解问题,我们应该很直观的会有一个想法,那就是最大流能不能搞?
事实证明这个方法是可行的,我们用folyd预处理求出两点间的最短距离,然后二分距离,如果当前距离是我们构成的流的最大值等于牛的个数那么证明当前距离是可行的方案,然后继续二分直至结束。
至于怎么构图呢?我们可以设立一个超级源点和超级汇点,然后把所有的挤奶器和源点建立一条容量为M的边,所有挤奶器和牛建立一天容量为1的边,所有牛和汇点建立一条边即可。
一个不错的最大流和二分答案的结合。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 350;
int head[maxn],level[maxn],cnt,Max_Flow;
struct Info{
int from,to,c,flow,next;
}edge[maxn*maxn*2];
void ADD(int u,int v,int w){
edge[cnt].from = u;
edge[cnt].to = v;
edge[cnt].c = edge[cnt].flow = w;
edge[cnt].next = head[u];
head[u] = cnt++;
edge[cnt].from = v;
edge[cnt].to = u;
edge[cnt].c = edge[cnt].flow = 0;
edge[cnt].next = head[v];
head[v] = cnt++;
}
int K,C,M,dist[maxn][maxn];
void Make_map(int Max_dist){
memset(head,-1,sizeof(head));
cnt = Max_Flow = 0;
for(int i = 1; i <= K; i++)
ADD(i,K+C+1,M);
for(int i = K+1; i <= K+C; i++)
ADD(0,i,1);
for(int i = K+1; i <= K+C; i++)
for(int j = 1; j <= K; j++)
if(dist[i][j] <= Max_dist)
ADD(i,j,1);
}
int floyd(){
int max_dist = 0;
for(int k = 1; k <= K+C; k++)
for(int i = 1; i <= K+C; i++){
if(dist[i][k] == INF)continue;
for(int j = 1; j <= K+C; j++){
if(dist[k][j] < INF){
dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]);
max_dist = max(max_dist,dist[i][j]);
}
}
}
return max_dist;
}
int bfs(int S,int E){
memset(level,-1,sizeof(level));
queue<int>Q;
level[S] = 0;
Q.push(S);
while(!Q.empty()){
int u = Q.front();
Q.pop();
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].to;
if(level[v] == -1 && edge[i].flow > 0){
level[v] = level[u]+1;
Q.push(v);
if(v == E)
return 1;
}
}
}
return 0;
}
int Find(int now,int flow,int E){
if(now == E)
return flow;
int os = flow;
for(int i = head[now]; ~i; i = edge[i].next){
int v = edge[i].to;
if(level[v] == level[now]+1 && edge[i].flow > 0){
int temp = Find(v,min(flow,edge[i].flow),E);
if(!temp)continue;
edge[i].flow -= temp;
edge[i^1].flow += temp;
flow -= temp;
}
}
return os-flow;
}
int Dinic(int S,int E){
while(bfs(S,E)){
int temp = Find(S,INF,E);
Max_Flow += temp;
}
return Max_Flow;
}
int main(){
while(~scanf("%d %d %d",&K,&C,&M)){
memset(dist,0,sizeof(dist));
for(int i = 1; i <= K+C; i++)
for(int j = 1; j <= K+C; j++){
scanf("%d",&dist[i][j]);
if(dist[i][j] == 0)
dist[i][j] = INF;
}
int l = 0,r = floyd();
int S = 0,E = C+K+1,ans;
while(l <= r){
int Mid = (l+r)>>1;
Make_map(Mid);
int res = Dinic(S,E);
if(res == C){
ans = Mid;
r = Mid-1;
}
else
l = Mid+1;
}
printf("%d\n",ans);
}
return 0;
}