Luogu3297 SDOI2013逃考(半平面交+最短路)
Posted gloid
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu3297 SDOI2013逃考(半平面交+最短路)相关的知识,希望对你有一定的参考价值。
把每个人的监视范围看成点,相邻的两个监视范围连边,那么跑一遍最短路就可以了(事实上边权都为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 ",bfs(S)); } return 0; }
以上是关于Luogu3297 SDOI2013逃考(半平面交+最短路)的主要内容,如果未能解决你的问题,请参考以下文章