题目传送门
题目大意:
先给你三个数,n,m,k,分别表示挤奶机的个数n,奶牛的个数m,还有每个挤奶机最多能挤k个奶牛。
然后给你了一个e(n+m)*(n+m)的矩阵,1~n表示挤奶机,n+1到m表示奶牛,e[i][j]表示i到j之间的距离。然后让你求的是所有的奶牛都挤奶,所有奶牛走的距离的最大值尽可能的小,然后输出这个最小值。
思路
先用floyd来把整张图跑一遍,求出任意两点的最小距离。然后构建二分图,机器和奶牛之间为两个集合,然后让你求最大值的最小值,肯定是用二分答案ans,判断是否符合,在构建奶牛和机器二分图的时候,如果当前枚举的最小距离为limit,那么奶牛和机器之间的距离大于limit的话就是不能匹配,小于limit就说是可以匹配,然后匈牙利跑就可以了。
wa了好久,最后怎么也没想到是floyd出锅了(傻掉了都)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int e[500][500];
int n,m,l;
struct zxc
{
int num;
int k[500];
}line[500];
int oo=1e8;
int vis[500];
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++)
{
// if(e[i][j]==oo)
// {
// continue;
// }
{
if(e[i][j]>e[i][k]+e[k][j])
{
e[i][j]=e[i][k]+e[k][j];
}
}
// printf("%d ",e[i][j]);
}
// printf("\n");
}
}
int erft(int u,int limit)
{
for(int i=1;i<=n;i++)
{
if(!vis[i]&&e[u][i]<=limit)//小于枚举的限制就说明可以链接。
{
vis[i]=1;
if(line[i].num<l)//小于匹配数量,还可以匹配。
{
line[i].k[line[i].num++]=u;
return 1;
}
for(int j=0;j<l;j++)//达到匹配数量,看看有没有可以腾开的。
{
if(erft(line[i].k[j],limit))
{
line[i].k[j]=u;
return 1;
}
}
}
}
return 0;
}
int fin(int limit)
{
memset(line,0,sizeof(line));
for(int i=1+n;i<=n+m;i++)
{
memset(vis,0,sizeof(vis));
if(!erft(i,limit))//有一个奶牛不能被挤奶,那么当前的枚举的就不符合要求。
{
return 0;
}
}
return 1;
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&l))
{
memset(e,0,sizeof(e));
int w=n+m;
for(int i=1;i<=w;i++)
{
for(int j=1;j<=w;j++)
{
scanf("%d",&e[i][j]);
if(e[i][j]==0)
{
e[i][j]=oo;
}
}
}
floyd();
int l=1,r=1e8;
int ans=10000000;
while(l<=r)//二分答案
{
int mid=(l+r)/2;
if(fin(mid))
{
r=mid-1;
ans=mid;
}
else
{
l=mid+1;
}
}
printf("%d\n",ans);
}
return 0;
}