洛谷传送门
BZOJ传送门
解析:
我们首先二分答案。
然后判断如果一条飞船在时限内甚至飞不到圆周上就肯定gg了。
如果能的话,我们将圆周分为 n n n等份,第一份是从 x x x轴开始的 1 / n 1/n 1/n圆,我们看这条飞船能不能飞到整个圆,如果能,就和每个区间连一条边。
如果不能我们将它和整个圆匹配,就先记录哪些区间的端点是能够匹配的,然后记录下匹配的最左端点和未匹配的最左端点。
跑二分图最大匹配,如果 n n n个位置全部能匹配的话,答案合法。
否则,我们开始将这个圆旋转,显然,旋转 α \alpha α弧度和旋转 α + 2 π n \alpha+\frac{2\pi}n α+n2π弧度是没有区别的,我们将刚才记录的所有左端点记录一下,上极角序扫描线,然后看旋转过程中那些位置失去了匹配资格,哪些端点拥有了匹配资格。
对于失去匹配资格的,我们在二分图上进行退流操作,对于拥有了匹配资格的,就加边后再在残量网络上跑一次最大流更新匹配数。
正确性比较显然,也比较好写,目前拿到BZOJrk1和洛谷rk1
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
re bool f=0;
while(!isdigit(c=gc()))if(c=='-')f=1;re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
}
using namespace IO;
cs int N=605;
struct edge{
int to,rev,cap;
edge(cs int &_to,cs int &_rev,cs int &_cap):to(_to),rev(_rev),cap(_cap){}
};
vector<edge> G[N];
inline void addedge(int u,int v,int val){
G[u].push_back(edge(v,G[v].size(),val));
G[v].push_back(edge(u,G[u].size()-1,0));
}
int S,T;
int lev[N];
vector<edge>::iterator cur[N];
inline bool BFS(){
memset(lev,-1,sizeof(int)*(T+1));
for(int re i=0;i<=T;++i)cur[i]=G[i].begin();
queue<int,list<int> > q;
q.push(S),lev[S]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(vector<edge>::iterator e=G[u].begin();e!=G[u].end();++e){
if(e->cap&&lev[e->to]==-1){
lev[e->to]=lev[u]+1;
if(e->to==T)return true;
q.push(e->to);
}
}
}
return false;
}
inline int Dinic(cs int &u,cs int &flow){
if(u==T)return flow;
int ans=0;
for(vector<edge>::iterator &e=cur[u];e!=G[u].end();++e){
if(e->cap&&lev[e->to]>lev[u]){
int delta=Dinic(e->to,min(flow-ans,e->cap));
e->cap-=delta;G[e->to][e->rev].cap+=delta;
if((ans+=delta)==flow)return ans;
}
}
lev[u]=-1;
return ans;
}
int flow;
inline void Flow(){while(BFS())flow+=Dinic(S,0x3f3f3f3f);}
inline void pop_flow(int u,int v){
vector<edge>::iterator it;
bool flag;
for(it=G[u].begin();it!=G[u].end();++it)
if(it->to==v){
flag=it->cap;
it=G[u].erase(it);
break;
}
for(;it!=G[u].end();++it)G[it->to][it->rev].rev--;
for(it=G[v].begin();it!=G[v].end();++it)
if(it->to==u){
it=G[v].erase(it);
break;
}
for(;it!=G[v].end();++it)G[it->to][it->rev].rev--;
if(flag)return ;
--flow;
for(it=G[S].begin();it!=G[S].end();++it)
if(it->to==u){
it->cap^=1;
G[u][it->rev].cap^=1;
break;
}
for(it=G[T].begin();it!=G[T].end();++it)
if(it->to==v){
it->cap^=1;
G[v][it->rev].cap^=1;
break;
}
Flow();
}
cs double PI=acos(-1);
cs double eps=1e-6;
struct Point{
double x,y;
Point(){}
Point(cs double &_x,cs double &_y):x(_x),y(_y){}
friend Point operator+(cs Point &a,cs Point &b){return Point(a.x+b.x,a.y+b.y);}
friend Point operator-(cs Point &a,cs Point &b){return Point(a.x-b.x,a.y-b.y);}
friend double operator*(cs Point &a,cs Point &b){return a.x*b.y-a.y*b.x;}
double norm()cs{return sqrt(x*x+y*y);}
}p[N];
struct data{
double t;
int u,v,op;
data(){}
data(cs double &_t,cs int &_u,cs int &_v,cs int &_op):t(_t),u(_u),v(_v),op(_op){}
friend bool operator<(cs data &a,cs data &b){
return a.t==b.t?a.op>b.op:a.t<b.t;
}
}q[N];
int cnt,n;
double radius,block;
inline bool check(double X){
cnt=0;flow=0;
for(int re i=0;i<=T;++i)G[i].clear();
for(int re i=1;i<=n;++i){
double len=p[i].norm();
if(fabs(radius-len)>X)return false;
if(len+radius<=X)for(int re j=1;j<=n;++j)addedge(i,j+n,1);
else {
double re ang1=atan2(p[i].y,p[i].x);
double re ang2=acos((radius*radius+len*len-X*X)/(2*radius*len));
double re al=ang1-ang2,ar=ang1+ang2;
while(al<0)al+=2*PI;
while(ar<0)ar+=2*PI;
int l=al/block,r=ar/block;
q[++cnt]=data(al-l*block,i,l+1+n,1);++l;
q[++cnt]=data(ar-r*block,i,r+1+n,0);++r;
if(l<=r)for(int re j=l+1;j<=r;++j)addedge(i,j+n,1);
else {
for(int re j=1;j<=r;++j)addedge(i,j+n,1);
for(int re j=l+1;j<=n;++j)addedge(i,j+n,1);
}
}
}
for(int re i=1;i<=n;++i)addedge(S,i,1),addedge(i+n,T,1);
Flow();
if(flow==n)return true;
sort(q+1,q+cnt+1);
for(int re i=1;i<=cnt;++i){
switch(q[i].op){
case 1:{
addedge(q[i].u,q[i].v,1);
Flow();
if(flow==n)return true;
break;
}
case 0:pop_flow(q[i].u,q[i].v);break;
}
}
return false;
}
double l,r=200;
signed main(){
n=getint();radius=getint();
block=2*PI/n;
S=0,T=2*n+1;
for(int re i=1;i<=n;++i){
p[i].x=getint();
p[i].y=getint();
}
while(l+1e-6<=r){
double mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
printf("%.8f",l);
return 0;
}