题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3199
题解:这题的关键在于怎么求出每个家长的监视范围呢?。其实很简单。对于第i个家长,向每个家长j连线作中垂线,每条线对应一个朝向i的半平面,这些半平面的交就是第i个家长的监视范围。然后半平面交出来的多边形每条变对应的家长j,与i连边,最后bfs一下求出起始多边形到界外的最短路就好了。时间复杂度O(n^2logn)。
题解说可以用V图做,可是我不会= =。最后吐槽一下这题O(n^2)的半平面交也是可以通过的。而且跑得没比nlogn的慢多少。囧。
代码:
/**************************************************************
Problem: 3199
User: hta
Language: C++
Result: Accepted
Time:844 ms
Memory:8844 kb
****************************************************************/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <list>
#include <queue>
#include <vector>
#include <ctime>
#include <set>
#include <bitset>
#include <deque>
#include <fstream>
#include <stack>
#include <map>
#include <utility>
#include <cassert>
#include <string>
#include <iterator>
#include <cctype>
using namespace std;
const int maxn=800,maxm=maxn*maxn;
const double eps=1e-9;
struct Tpoint
{
double x,y;
Tpoint(){}
Tpoint(double _x,double _y){x=_x,y=_y;}
Tpoint operator -(const Tpoint &b)const{return Tpoint(x-b.x,y-b.y);}
Tpoint operator +(const Tpoint &b)const{return Tpoint(x+b.x,y+b.y);}
Tpoint operator *(double b)const{return Tpoint(x*b,y*b);}
double operator *(const Tpoint &b)const{return x*b.y-y*b.x;}
}S,p[maxn];
struct Tline
{
Tpoint p1,p2;int id;
double ang;
Tline(){}
Tline(Tpoint _p1,Tpoint _p2,int i){p1=_p1,p2=_p2;ang=atan2(p2.y-p1.y,p2.x-p1.x);id=i;}
}L[maxn];
double xx,yy;
bool flag,vis[maxn];
int T,n,tot=0,Q[maxn],pre[maxm],t[maxm],Link[maxn],s[maxm],d[maxn],cnt=0;
inline int get()
{
int f=0,v=0;char ch;
while(!isdigit(ch=getchar()))if(ch=='-')break;
if(ch=='-')f=1;else v=ch-48;
while(isdigit(ch=getchar()))v=v*10+ch-48;
if(f==1)return -v;else return v;
}
inline int sig(double x){return fabs(x)<=eps?0:(x>eps?1:-1);}
inline double dist(const Tpoint &a){return sqrt(a.x*a.x+a.y*a.y);}
Tpoint lineintersect(const Tline &l1,const Tline &l2)
{
double ta=(l1.p2-l2.p1)*(l1.p1-l2.p1);
double tb=(l2.p2-l1.p2)*(l1.p1-l1.p2);
Tpoint tp;
if(sig(ta+tb)==0){flag=0;return tp;};
tp=(l2.p2-l2.p1)*(ta/(ta+tb))+l2.p1;
return tp;
}
bool cmp(const Tline &a,const Tline &b)
{
if(sig(a.ang-b.ang)==0)return sig((a.p1-b.p1)*(b.p2-b.p1))<0;
return sig(a.ang-b.ang)<0;
}
bool onleft(const Tline &l1,const Tline &l2,const Tline &l3)
{
Tpoint tp=lineintersect(l1,l2);
return sig((tp-l3.p1)*(l3.p2-l3.p1))<=0;//
}
void hpi(int x)
{
flag=1;
sort(L+1,L+1+tot,cmp);
int tp=1,front=1,rear=0;
for(int i=2;i<=tot;i++)
if(sig(L[i].ang-L[i-1].ang)!=0)L[++tp]=L[i];
tot=tp;
for(int i=1;i<=tot;i++)
{
while(front<rear&&!onleft(L[Q[rear-1]],L[Q[rear]],L[i]))rear--;
while(front<rear&&!onleft(L[Q[front]],L[Q[front+1]],L[i]))front++;
if(!flag)return;
Q[++rear]=i;
}
while(front<rear&&!onleft(L[Q[rear-1]],L[Q[rear]],L[Q[front]]))rear--;
while(front<rear&&!onleft(L[Q[front]],L[Q[front+1]],L[Q[rear]]))front++;
if(!flag)return;
if(rear-front<2)return;
for(int i=front;i<=rear;i++)
{
int y=L[Q[i]].id;
pre[++cnt]=Link[x]; Link[x]=cnt; t[cnt]=y;
}
}
void work(int x)
{
tot=0;
L[++tot]=Tline(Tpoint(0,0),Tpoint(xx,0),n+1);
L[++tot]=Tline(Tpoint(xx,0),Tpoint(xx,yy),n+1);
L[++tot]=Tline(Tpoint(xx,yy),Tpoint(0,yy),n+1);
L[++tot]=Tline(Tpoint(0,yy),Tpoint(0,0),n+1);
for(int i=1;i<=n;i++)
{
if(i==x)continue;
Tpoint S=(p[i]+p[x])*0.5,tp=Tpoint(p[x].y-p[i].y,-(p[x].x-p[i].x)),T=S+tp;
L[++tot]=Tline(S,T,i);
}
hpi(x);
}
int bfs(int st)
{
int front=0,rear=1;
memset(d,120,sizeof(d));
memset(vis,0,sizeof(vis));
d[st]=0;vis[st]=1;s[front]=st;
while(front!=rear)
{
int p=s[front];
for(int i=Link[p];i;i=pre[i])
if(!vis[t[i]])d[t[i]]=d[p]+1,vis[t[i]]=1,s[rear++]=t[i];
front++;
if(d[n+1]<n+10)break;
}
return d[n+1];
}
int main()
{
T=get();
while(T--)
{
n=get();
xx=get(),yy=get(),S.x=get(),S.y=get();
for(int i=1;i<=n;i++)p[i].x=get(),p[i].y=get();
cnt=0,memset(Link,0,sizeof(Link));
for(int i=1;i<=n;i++)work(i);
int st=1;double tp=dist(p[1]-S);
for(int i=2;i<=n;i++)
if(dist(p[i]-S)<tp)tp=dist(p[i]-S),st=i;
printf("%d\n",bfs(st));
}
return 0;
}