因为问题是单调的,R小肯定匹配的少,R大肯定匹配的多,所以一眼可以二分+二分图匹配。
难点就在要求最小值和最大值,最小值好求,但是最大值呢?
因为二分图匹配算法是求得最大匹配,我们就可以吧找最大值的问题(也就最小失配)转化为求剩余的最大匹配,注意建边的条件要反过来。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define eps 1e-7
using namespace std;
struct node
{
double x,y;
}A[51],B[51];
struct edge
{
int x,y,next;
}a[3100];int len,last[110];
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int match[110];
int chw[110];
int n,k;
bool findmuniu(int x,int i)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(chw[y]!=i)
{
chw[y]=i;
if(match[y]==0||findmuniu(match[y],i)==true)
{
match[y]=x;
return true;
}
}
}
return false;
}
int check(double x,int opt)
{
len=0;memset(last,0,sizeof(last));
if(opt==1)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(x-sqrt((A[i].x-B[j].x)*(A[i].x-B[j].x)+(A[i].y-B[j].y)*(A[i].y-B[j].y))>eps)
{
ins(i,j+n);
}
}
}
}
else
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(sqrt((A[i].x-B[j].x)*(A[i].x-B[j].x)+(A[i].y-B[j].y)*(A[i].y-B[j].y))-x>=eps)
{
ins(i,j+n);
}
}
}
}
int t=0;
memset(chw,0,sizeof(chw));
memset(match,0,sizeof(match));
for(int i=1;i<=n;i++)
{
if(findmuniu(i,i)==true) t++;
}
return t;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%lf%lf",&A[i].x,&A[i].y);
for(int i=1;i<=n;i++) scanf("%lf%lf",&B[i].x,&B[i].y);
double l=0.0,r=99999999.9,ans;
while(r-l>=eps)//最小值
{
double mid=(l+r)/2;
int t=check(mid,1);
if(t>=k)
{
if(t==k) ans=mid;
r=mid-eps;
}
else l=mid+eps;
}
printf("%.2lf ",ans);
if(n==k)//如果n==k那就是都要匹配的话,+INF是最大的
{
printf("+INF\n");
return 0;
}
l=0.0,r=99999999.9;
while(r-l>=eps)//最大值
{
double mid=(l+r)/2;
int t=check(mid,2);
if(t==n-k) ans=mid;
if(t<n-k)//最小失配等效于剩余的最大匹配(也就是n-k的最大匹配)
{
r=mid-eps;
}
else l=mid+eps;
}
printf("%.2lf\n",ans);
return 0;
}