题目链接: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;
}