题意:K个产奶机,C头奶牛,每个产奶机最多可供M头奶牛使用;并告诉了产奶机、奶牛之间的两两距离Dij(0<=i,j<K+C)。
问题:如何安排使得在任何一头奶牛都有自己产奶机的条件下,奶牛到产奶机的最远距离最短?最短是多少?
解题思路:首先用Floyd把两两之间的最小距离算出来,接下来二分枚举最短距离limit,只要i,j两点之间距离小于limit,连一条容量为1的边,源点到产奶机的边为M,限制了每个产奶机最多供M头奶牛。奶牛到汇点的边为1,表示每头牛都有一个产奶机。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 250;
const int inf = 0x3f3f3f3f;
struct Edge
{
int to,next,flow;
}edge[maxn*maxn];
int n,m,c,dis[maxn][maxn];
int head[maxn],cnt;
int level[maxn],st,ed;
void addedge(int u,int v,int flow)
{
edge[cnt].to = v;
edge[cnt].flow = flow;
edge[cnt].next = head[u];
head[u] = cnt++;
swap(u,v);
edge[cnt].to = v;
edge[cnt].flow = 0;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void floyd()
{
for(int k = 1; k <= n + m; k++)
for(int i = 1; i <= n + m; i++)
for(int j = 1; j <= n + m; j++)
dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
}
void build(int limit)
{
cnt = 0;
memset(head,-1,sizeof(head));
for(int i = 1; i <= n; i++)
addedge(st,i,c);
for(int i = n + 1; i <= n + m; i++)
addedge(i,ed,1);
for(int i = 1; i <= n; i++)
for(int j = n + 1; j <= n + m; j++)
if(dis[i][j] <= limit)
addedge(i,j,1);
}
int BFS(int src,int des){
queue<int> q;
memset(level,0,sizeof(level));
level[src] = 1;
q.push(src);
while(!q.empty()){
int u = q.front();
q.pop();
if(u==des) return 1;
for(int k = head[u];k!=-1;k=edge[k].next){
int v = edge[k].to,w = edge[k].flow;
if(level[v] == 0 && w != 0){
level[v]=level[u]+1;
q.push(v);
}
}
}
return -1;
}
int dfs(int u,int des,int increaseRoad){
if(u == des) return increaseRoad;
int ret = 0;
for(int k=head[u];k!=-1;k=edge[k].next){
int v = edge[k].to, w = edge[k].flow;
if(level[v]==level[u]+1&&w!=0){
int MIN = min(increaseRoad-ret,w);
w = dfs(v,des,MIN);
if(w > 0)
{
edge[k].flow -=w;
edge[k^1].flow +=w;
ret += w;
if(ret == increaseRoad) return ret;
}
else level[v] = -1;
}
}
return ret;
}
int Dinic(int src,int des){
int ans = 0;
while(BFS(src,des)!=-1) ans += dfs(src,des,inf);
return ans;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&c)!=EOF)
{
st = 0, ed = n + m + 1;
for(int i = 1; i <= n + m; i++)
for(int j = 1; j <= n + m; j++)
{
scanf("%d",&dis[i][j]);
if(dis[i][j] == 0)
dis[i][j] = inf;
}
floyd();
int l = 1,r = inf,mid,ans;
while(l <= r)
{
mid = (l + r) >> 1;
build(mid);
int tmp = Dinic(st,ed);
if(tmp == m)
{
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
printf("%d\n",ans);
}
return 0;
}