题目链接:http://poj.org/problem?id=2112
题意是有k台挤奶机,c头奶牛,每台挤奶机最多可以给m奶头牛挤奶,1--k是挤奶机的编号,k+1--k+c是奶牛的编号,然后输入一个邻接矩阵,表示它们任意两点间的距离,问这些奶牛去挤奶机的过程中,跑的最远的一头奶牛的最小距离是多少。
思路就是我们先存边,然后对于距离为0的是不可到达的边,赋值为inf就好,然后先跑一遍Floyd求出任意两点的最短距离,然后用二分去枚举上下界,去判断是否符合二分图的多重匹配就好了。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#define maxn 250
#define inf 0x3f3f3f3f
using namespace std;
struct Node{
int cnt;
int k[maxn];
}link[maxn];
bool maps[maxn][maxn];
bool vis[maxn];
int pre[maxn][maxn];
int k,c,m,Max;
void Floyd(){
for(int p=1;p<=k+c;p++){
for(int i=1;i<=k+c;i++){
for(int j=1;j<=k+c;j++){
if(pre[i][j] > pre[i][p] + pre[p][j]){
pre[i][j] = pre[i][p] + pre[p][j];
}
}
}
}
}
bool dfs(int u){
for(int i=1;i<=k;i++){
if(vis[i] == false && maps[i][u] == true){
vis[i] = true;
if(link[i].cnt < m){
link[i].k[ ++ link[i].cnt ] = u;
return true;
}
for(int j=1;j<=link[i].cnt;j++){
if(dfs(link[i].k[j])){
link[i].k[j] = u;
return true;
}
}
}
}
return false;
}
bool solve(int limit){
memset(maps, false, sizeof(maps));
memset(link, 0 ,sizeof(link));
for(int i=1;i<=k;i++){
for(int j=k+1;j<=k+c;j++){
if(pre[i][j] <= limit){
maps[i][j-k] = true;
}
}
}
for(int i=1;i<=c;i++){
memset(vis,false,sizeof(vis));
if(!dfs(i)) return false;
}
return true;
}
int main()
{
while(scanf("%d%d%d",&k,&c,&m) != -1){
Max = 0;
for(int i=1;i<=k+c;i++){
for(int j=1;j<=k+c;j++){
scanf("%d",&pre[i][j]);
if(pre[i][j] == 0) pre[i][j] = inf;
}
}
Floyd();
for(int i=1;i<=k;i++){
for(int j=k+1;j<=k+c;j++){
Max = max(Max, pre[i][j]);
}
}
int l = 0, r = Max, mid;
// int ans = Max;
while(l < r){
mid = (l + r) >> 1;
if(solve(mid)){
r = mid;
// ans = mid;
}
else l = mid + 1;
}
printf("%d\n", r);
}
return 0;
}