题目链接:Easter Eggs
显然可以二分。
然后怎么check呢?显然我们把距离小于mid的点连起来,那么就相当于找一个最大独立集,然后最大独立集的个数要大于等于n。
然后因为连边的只是蓝色和红色之间,所以这是一个二分图,之间匈牙利即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=510;
int n,B,R,x[N],y[N],mat[N],vis[N];
vector<int> g[N];
inline double dis(int i,int j){
return sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
int dfs(int x){
for(auto to:g[x]) if(!vis[to]){
vis[to]=1;
if(!mat[to]||dfs(mat[to])){
mat[to]=x; return 1;
}
}
return 0;
}
inline int check(double mid){
int res=0; memset(mat,0,sizeof mat);
for(int i=1;i<=B;i++) g[i].clear();
for(int i=1;i<=B;i++) for(int j=B+1;j<=B+R;j++)
if(dis(i,j)<mid) g[i].push_back(j);
for(int i=1;i<=B;i++) memset(vis,0,sizeof vis),res+=dfs(i);
return B+R-res>=n;
}
signed main(){
cin>>n>>B>>R;
for(int i=1;i<=B;i++) cin>>x[i]>>y[i];
for(int i=B+1;i<=B+R;i++) cin>>x[i]>>y[i];
double l=0.0,r=1e5;
for(int i=1;i<=50;i++){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.10lf\n",l);
return 0;
}