首先固然是二分答案\(mid\),
对于每个点,以它为圆心的圆,交上攻击轨道;
那么这个点到攻击轨迹的可达范围就是一段圆弧。c++
怎么求这段圆弧呢?网络
咱们知道圆弧能够用其两端点对于圆心的弧度(角度)来表示。
已知三角形的三边\(R1,R2,Dist\),利用余弦定理,咱们能够求出角\(θ\)。
而后咱们也能够轻易得知\(C\)对于圆心\(A\)的弧度\(α\)。
那么圆弧两端点的弧度分别为\(α±θ\)。dom
假设一个圆弧覆盖正多边形的顶点,那么称圆弧和这个顶点能够匹配。
如今就是问:有没有一个攻击轨道内接正多边形偏转角度,
使得圆弧和正多边形的顶点存在完美匹配。spa
假设如今存在一种可行的方案,
若是这个正多边形没有一个顶点与某一个圆弧的一个端点重合的话,
那么我能够抖动这个正多边形直到其的一个顶点与某一个圆弧的一个端点重合为止,
这个我是想说,若是存在可行的方案,那么必定存在一种可行的方案,使得该正多边形有一个顶点与某个圆弧的一个端点重合。
因为圆弧的端点的个数有\(O(n)\),
因此枚举重合的那个端点,而后就能够经过这个端点肯定正多边形的其余顶点。
而后就能够建出二分图,问是否有完美匹配了,完美匹配能够用\(Hungary\)或\(Maxflow\),\(O(n^3)\)解决。
复杂度是\(O(n^4 log n)\)的,能够过50分。code
首先咱们注意到,
虽然每一个圆弧的端点对应一种偏转角度,
这些偏转角度彷佛遍及\(360°\),但其实这些偏转角度是能够\(mod 2*π/n\)的,由于正多边形的顶点互相等价。
因此说咱们实际的最大偏转角度是不超过\(2*π/n\)。blog
先把全部偏转角度\(mod 2*π/n\)后,从小到大排序。
对于一个圆弧而言,因为最大的偏转角度不超过相邻两顶点间距,
因此在偏转过程当中,不能变得能匹配的顶点不超过\(1\)个,能变得不能匹配的顶点不超过\(1\)个。
也就是说,从\(0\)到最大偏转角度对应的残留网络的变化容量的边不超过\(2*n\)条。
因此咱们利用网络流的退流,来只对残留网络进行局部修改。排序
具体而言:
1.删边
好比说一条\((u,v)\)的边容量变为\(0\),那么假如这条边有\(x\)的流量,那么确定要把最大流减掉\(x\)。
而后要把这条边的双向容量归零。
从\(u\)到\(1\)找出总流量为\(x\)的增广路,把它们都流量翻转;这个能够直接用最大流来实现,限制住初始进入的流量不超过\(x\)便可;
同理,从\(T\)到\(v\)跑一遍最大流。
最后还要从\(1\)到\(T\)检查有没有别的增广路。
2.加边
这个直接加就行了,最后也要检查从\(1\)到\(T\)有没有新增的增广路。it
一次退流/加边操做就是\(O(m)\)的,在本题中\(m=n^2(n?)\)
因为每一个点只有一次会退流/加边,因此总共是\(O(n^3)\)。
加上预处理的网络流是\(O(n^3)\)的。ast
加上二分,总共是\(O(n^3 log n)\)。class
#include<bits/stdc++.h> #define ll long long #define db double #define fo(i,x,y) for(int i=x;i<=y;i++) #define fd(i,x,y) for(int i=x;i>=y;i--) using namespace std; const int maxn=407,maxm=maxn*maxn; const db pi=acos(-1); int n,m,Last=1; db Step; struct P{ int x,y; }a[maxn]; void Init(){ scanf("%d%d",&n,&m); fd(i,n,1) scanf("%d%d",&a[i].x,&a[i].y); //random_shuffle(a+1,a+n+1); Step=2*pi/n; } int N; db q[maxn*2],L[maxn],R[maxn]; void newQuery(db x){ while (x>=-pi+Step) x-=Step; while (x<-pi) x+=Step; q[++N]=x; } int fi[maxn],ne[maxm],la[maxm],va[maxm],tot,T; void add(int a,int b,int c){ tot++; ne[tot]=fi[a]; la[tot]=b; va[tot]=c; fi[a]=tot; } void Add(int a,int b,int c){ add(a,b,c); add(b,a,0); } int bz[maxn],id; int sap(int v,int flow){ bz[v]=id; if (v==T) return flow; for(int k=fi[v];k;k=ne[k]) if (bz[la[k]]<id && va[k]){ int i=sap(la[k],va[k]&flow); if (i){ va[k]-=i; va[k^1]+=i; return i; } } return 0; } int go_flow(int St,int Next,int Lim=0x7fffffff){ int res=0; T=Next; while (1){ id++; int temp=sap(St,1); if (temp){ res+=temp; if (res==Lim) break; }else break; } return res; } int Road[maxn][maxn],res; int cnt[maxn]; bool check(db ang){ fo(j,1,n){ if (cnt[j]>=2) continue; db y=ang; fo(i,1,n){ if (L[j]>R[j] && (L[j]<=y && y<=R[j]+pi*2 || L[j]-pi*2<=y && y<=R[j]) || L[j]<=R[j] && L[j]<=y && y<=R[j]){ if (!Road[j][i]){ Add(1+j,1+n+i,1); Road[j][i]=tot; //cnt[j]++; /*int z=go_flow(1+n+i,n+n+2)&go_flow(1,1+j); res+=z; va[tot]^=z; va[tot^1]^=z;*/ if (cnt[j]){ cnt[j]++; break; } } }else{ if (Road[j][i]){ int k=Road[j][i]; if (va[k]){ va[k]=va[k^1]=0; go_flow(n+n+2,1+n+i,1); go_flow(1+j,1,1); res--; } va[k^1]=va[k]=0; Road[j][i]=0; cnt[j]++; } } y+=Step; } } res+=go_flow(1,n+n+2); return res>=n; } bool judge(db rad){ tot=1; res=0; memset(fi,0,sizeof fi); memset(cnt,0,sizeof cnt); fo(i,1,n) Add(1,1+i,1); fo(i,1,n) Add(1+n+i,n+n+2,1); memset(Road,0,sizeof Road); N=0; fo(i,1,n){ db Dist=sqrt(a[i].x*a[i].x+a[i].y*a[i].y); if (rad+m<Dist || Dist<m-rad || a[i].x==0 && a[i].y==0 && rad<m) return false; if (rad<m+Dist){ db Alpha=atan2(a[i].y,a[i].x),Beta=acos((m*m+Dist*Dist-rad*rad)/(2.0*m*Dist)); L[i]=Alpha-Beta; R[i]=Alpha+Beta; if (L[i]<-pi) L[i]+=2*pi; if (R[i]>=pi) R[i]-=2*pi; }else{ L[i]=-pi; R[i]=pi; } newQuery(L[i]); newQuery(R[i]); } sort(q+1,q+N+1); if (n<=10){ fo(i,1,N) if ((i==Last || q[i]-q[i-1]>1e-7) && check(q[i])){ Last=i; //printf("%d\n",i); return true; } return false; } /*fd(i,N,1) if ((i==N || q[i+1]-q[i]>1e-7) && check(q[i])){ printf("%d\n",i); return true; }*/ fo(i,Last,N) if ((i==Last || q[i]-q[i-1]>1e-7) && check(q[i])){ Last=i; //printf("%d\n",i); return true; } fo(i,1,Last-1) if ((i==1 || q[i]-q[i-1]>1e-7) && check(q[i]+Step)){ //Last=i; //printf("%d\n",i); return true; } return false; } db Ans; void Solve(){ db l=0,r=200; while (r-l>1e-7){ db mid=(l+r)/2; if (judge(mid)) r=mid; else l=mid; } Ans=l; } void Print(){ printf("%.8lf\n",Ans); } int main(){ freopen("3.in","r",stdin); freopen("3.out","w",stdout); Init(); Solve(); Print(); return 0; }