题目链接:http://poj.org/problem?id=2112
题目翻译:有K个挤奶机,每个挤奶机可以容纳M头牛,总共有C头牛要挤奶,问C头牛中怎样分配可以使
走最远距离的那头牛走的距离尽量小,求出这个最远距离的最小值。
输入:K,M,C。 然后K+C的方阵表示各个物体间距离。
解题思路:网络流+二分。
先Flody求每个奶牛到每个挤奶机的最短距离。
每个奶牛只能去一个挤奶机器。
建立超级源点S,超级汇点D,由超级源点到每一头奶牛建立一条边,其容量就是1,代表1头牛,
由每台机器向超级汇点引一条边,其容量就是M,然后采用二分的方法求解答案,我们假设maxdist
是个挺大的数吧,然后如果dist[i][j] 也就是第i头牛到第j个挤奶机器的最短路小于maxdist,则我们
可以建一条边由第i头牛到第j头牛,其容量为1,然后我们求这个图的最大流,如果我们发现当前最
大流是C,则说明所有的牛都已经有相应的挤奶机器挤奶,我们可以缩小这个maxdist看看答案范围
能够缩小,如果最大流小于C则,我们就要扩大maxdist,来找符合题目的距离。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
int Map[240][240],head[240],level[240],vis[240],cap[240][240];
int K,C,M,S,D,maxdist,edgeNumber,minFlow,minFlowNode,maxFlow; ///K台挤奶机,C头奶牛,每个机器可以容纳M头奶牛
void Flody() {
for(int k = 1; k <= K+C; k++)
for(int i = 1; i <= K+C; i++)
for(int j = 1; j <= K+C; j++) {
if(Map[i][k] + Map[k][j] < Map[i][j])
Map[i][j] = Map[i][k] + Map[k][j];
}
}
bool bfs() {
queue<int>qu;
memset(level,-1,sizeof(level));
level[S] = 0;
qu.push(S);
while(!qu.empty()) {
int u = qu.front();
qu.pop();
for(int i = 0; i <= K+C+1; i++) {
if(level[i]==-1 && cap[u][i] > 0) {
level[i] = level[u] + 1;
if(i == D)
return true;
qu.push(i);
}
}
}
return false;
}
void dfs() {
int u,v,cur,i;
deque<int>qu;
memset(vis,0,sizeof(vis));
vis[S] = 1;
qu.push_back(S);
while(!qu.empty()) {
cur = qu.back();
if(cur == D){
minFlow = INF+1;
minFlowNode = S;
for(i = 1; i < qu.size(); i++) {
u = qu[i-1];
v = qu[i];
if(cap[u][v]>0 && minFlow>cap[u][v]) {
minFlow = cap[u][v];
minFlowNode = u;
}
}
maxFlow += minFlow;
for(i = 1; i < qu.size(); i++) {
u = qu[i-1];
v = qu[i];
cap[u][v] -= minFlow;
cap[v][u] += minFlow;
}
while(!qu.empty() && qu.back() != minFlowNode) {
vis[qu.back()] = 0;
qu.pop_back();
}
}else {
for(i = 1; i <= K+C+1; i++) {
if(cap[cur][i]>0 && level[i] == level[cur]+1 && vis[i]==0) {
vis[i] = 1;
qu.push_back(i);
break;
}
}
if(i > K+C+1)
qu.pop_back();
}
}
}
///求最大流
void dinic() {
maxFlow = 0;
while(bfs()) {
dfs();
}
}
///建图
void buildGraph(int top)
{
memset(cap,0,sizeof(cap));
for(int i = K+1; i <= K+C; i++)
cap[S][i] = 1;
for(int i = 1; i <= K; i++)
cap[i][D] = M;
for(int i = K+1; i <= K+C; i++)
for(int j = 1; j <= K; j++) {
if(Map[i][j]<=top)
cap[i][j] = 1;
}
}
void solve() {
int ans = 1,low = 1,high = maxdist;
while(low <= high)
{
int mid = (low+high)/2;
buildGraph(mid);
dinic();
if(maxFlow == C) {
ans = mid;
high = mid - 1;
}else {
low = mid + 1;
}
}
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d%d%d",&K,&C,&M))
{
maxdist = 0;
for(int i = 1; i <= K+C; i++)
for(int j = 1; j <= K+C; j++){
scanf("%d",&Map[i][j]);
maxdist += Map[i][j];
if(Map[i][j] == 0 && i != j) ///二者之间没有道路
Map[i][j] = INF;
}
Flody();
S = 0;
D = K+C+1;
solve();
}
return 0;
}