1. 程式人生 > >Luogu3297 SDOI2013逃考(半平面交+最短路)

Luogu3297 SDOI2013逃考(半平面交+最短路)

半平面 rotate 同時 () a* 應該 半平面交 最優 urn

  把每個人的監視範圍看成點,相鄰的兩個監視範圍連邊,那麽跑一遍最短路就可以了(事實上邊權都為1可以直接bfs)。顯然最優的話不會有某個時刻同時被多人監視,要跨過去的話完全可以經過分界線而不是交點。

  現在問題是怎麽求出哪些監視範圍相鄰。考慮對於某個人的監視範圍求出所有與它相鄰的。兩個監視範圍的公共邊是這兩個人連線的中垂線,把這些線畫出來可以發現求個半平面交就好了。註意線要求在矩形範圍內。如果直線在半平面交中只剩下一個點應該去掉。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include
<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 610 #define vector dot int
T,n,p[N],d[N],queue[N],cnt; bool flag[N]; const double eps=1E-10; struct data{int to,nxt; }edge[N*N]; struct dot { double x,y; vector operator +(const vector&a) const { return (vector){x+a.x,y+a.y}; } vector operator -(const vector&a) const { return (vector){x-a.x,y-a.y}; }
double operator *(const vector&a) const { return x*a.y-y*a.x; } vector operator *(const double a) const { return (vector){a*x,a*y}; } double len() { return sqrt(x*x+y*y); } vector rotate() { return (vector){-y,x}; } }a[N],P[N]; struct line { dot a;vector p;int i; bool operator <(const line&a) const { return atan2(p.x,p.y)>atan2(a.p.x,a.p.y); } }q[N],Q[N]; void addedge(int x,int y){cnt++;edge[cnt].to=y,edge[cnt].nxt=p[x],p[x]=cnt;} bool onright(line x,dot y) { return (y-x.a)*x.p>=0; } dot cross(line x,line y) { return y.a+y.p*(x.p*(x.a-y.a)/(x.p*y.p)); } int bfs(int S) { memset(d,42,sizeof(d)); int head=0,tail=1;queue[1]=S;d[S]=0; do { int x=queue[++head]; for (int i=p[x];i;i=edge[i].nxt) if (d[x]+1<d[edge[i].to]) { d[edge[i].to]=d[x]+1; queue[++tail]=edge[i].to; if (!edge[i].to) return d[edge[i].to]; } }while (head<tail); } int main() { #ifndef ONLINE_JUDGE freopen("3297.in","r",stdin); freopen("3297.out","w",stdout); const char LL[]="%I64d"; #else const char LL[]="%lld"; #endif T=read(); while (T--) { n=read(); int r=read(),c=read(); dot s;s.x=read(),s.y=read(); for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(); int S; double dis=(a[1]-s).len(); for (int i=2;i<=n;i++) dis=min(dis,(a[i]-s).len()); for (int i=1;i<=n;i++) if (fabs(dis-(a[i]-s).len())<eps) S=i; cnt=0; memset(p,0,sizeof(p)); for (int j=1;j<=n;j++) { int t=0; for (int i=1;i<=n;i++) if (i!=j) q[++t]=(line){(a[i]+a[j])*0.5,(a[i]-a[j]).rotate(),i}; q[++t]=(line){(dot){0,0},(vector){1,0},0}; q[++t]=(line){(dot){r,0},(vector){0,1},0}; q[++t]=(line){(dot){r,c},(vector){-1,0},0}; q[++t]=(line){(dot){0,c},(vector){0,-1},0}; sort(q+1,q+t+1); int head=1,tail=1;Q[1]=q[1]; for (int i=2;i<=t;i++) { while (head<tail&&onright(q[i],P[tail])) tail--; while (head<tail&&onright(q[i],P[head+1])) head++; Q[++tail]=q[i]; if (fabs(Q[tail-1].p*Q[tail].p)<eps) { tail--; if (onright(q[i],Q[tail].a)) Q[tail]=q[i]; } if (head<tail) P[tail]=cross(Q[tail],Q[tail-1]); } while (head<tail&&onright(Q[head],P[tail])) tail--; P[head]=cross(Q[head],Q[tail]); for (int i=head;i<=tail;i++) addedge(j,Q[i].i); } printf("%d\n",bfs(S)); } return 0; }

Luogu3297 SDOI2013逃考(半平面交+最短路)