分析

好像叫V图什么的。

容易发现,对于每个点,其监视的范围就是这个点与其它所有点的垂直平分线分割平面后的半平面交。由于数据范围很小,所以我们可以直接枚举每个点,使用双端队列求出其监视的范围。若两个点的监视范围有公共边,那么就在这两个点之间连一条边,边权为\(1\)。然后从起点bfs一遍即可。

这里重点说一下求半平面交的细节,毕竟这是ErkkiErkko这个大菜鸡第一次写半平面交。

可以使用有向的直线,规定直线左侧的平面是合法的区域。

求两条有向直线的交点时,可以使用面积作为中间量进行转换,具体请参见代码。

如果两条直线方向相同,选更靠左的那一条,毕竟咱们求的是半平面交而不是半平面并,

说到半平面并,感觉可以通过高中数学里交补补并并补补交那套东西转化成半平面交来求解。

还有一个很重要的地方,因为是双端队列(或许也可以理解为,半平面交一般是围成一圈),所以在插入最后一条有向线段之后,要检查队尾两条直线的交点是否满足队首的直线,如果不满足就弹出队尾,直到满足为止。

半平面交进行极角排序的时候,直接用叉积来排的话会出很多奇奇怪怪的锅(因为叉积不满足偏序,大概吧,说错了不要喷ErkkiErkko,毕竟他这么菜),要用叉积的话必须分象限。还可以选择调用std::atan2()函数。这里最好预处理出来,而不要在cmp()函数中调用,否则会对常数有很大的影响(大概差\(7,8\)倍的样子,可怕)。

\(n\)对应的是横坐标不是纵坐标。

更具体的就看代码吧。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <queue>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl; inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
} const int MAXN=605;
int n,lcnt,hd,tl,ecnt,head[MAXN];
int s,dis[MAXN];
double R,C,sx,sy;
bool vis[MAXN],invalid[MAXN];
struct Edge{
int to,nxt;
}e[MAXN*MAXN]; inline void add_edge(int bg,int ed){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
} struct Po{
double x,y;
inline friend Po operator + (Po A,Po B){return (Po){A.x+B.x,A.y+B.y};}
inline friend Po operator - (Po A,Po B){return (Po){A.x-B.x,A.y-B.y};}
inline friend Po operator * (Po A,double B){return (Po){A.x*B,A.y*B};}
inline friend Po operator / (Po A,double B){return (Po){A.x/B,A.y/B};}
}re[MAXN];
inline int dcmp(double A,double B){return fabs(A-B)<1e-8?0:((A>B)*2)-1;}
inline Po getmid(Po A,Po B){return (Po){(A.x+B.x)/2,(A.y+B.y)/2};}
typedef Po Ve;
inline double getlen(Ve A){return sqrt(A.x*A.x+A.y*A.y);}
inline double getcross(Ve A,Ve B){return A.x*B.y-A.y*B.x;}
inline Ve getnor(Ve A){return (Ve){-A.y,A.x}/getlen(A);}
struct Li{
Po u;Ve v;int id;double ang;
inline friend bool operator < (Li A,Li B){return dcmp(A.ang,B.ang)<0;}
inline Po getp(double t){return u+v*t;}
}l[MAXN],que[MAXN];
inline Po getinter(Li A,Li B){return A.getp(getcross(B.v,A.u-B.u)/getcross(A.v,B.v));}
inline Li getpb(Po A,Po B,int id){return (Li){getmid(A,B),getnor(B-A),id,0};}
inline bool isleft(Po A,Li B){return dcmp(getcross(B.v,A-B.u),0)>0;} inline void solve(int x){
lcnt=0;
l[++lcnt]=(Li){(Po){0,0},(Ve){1,0},n+1,0},l[lcnt].ang=std::atan2(l[lcnt].v.y,l[lcnt].v.x);
l[++lcnt]=(Li){(Po){C,0},(Ve){0,1},n+1,0},l[lcnt].ang=std::atan2(l[lcnt].v.y,l[lcnt].v.x);
l[++lcnt]=(Li){(Po){C,R},(Ve){-1,0},n+1,0},l[lcnt].ang=std::atan2(l[lcnt].v.y,l[lcnt].v.x);
l[++lcnt]=(Li){(Po){0,R},(Ve){0,-1},n+1,0},l[lcnt].ang=std::atan2(l[lcnt].v.y,l[lcnt].v.x);
rin(i,1,n) if(!invalid[i]) if(i!=x) l[++lcnt]=getpb(re[x],re[i],i),l[lcnt].ang=std::atan2(l[lcnt].v.y,l[lcnt].v.x);
std::sort(l+1,l+lcnt+1);
hd=1,tl=0;
rin(i,1,lcnt){
while(hd<tl&&!isleft(getinter(que[tl-1],que[tl]),l[i])) tl--;
while(hd<tl&&!isleft(getinter(que[hd],que[hd+1]),l[i])) hd++;
if(hd<=tl&&dcmp(getcross(l[i].v,que[tl].v),0)==0){
if(isleft(l[i].u,que[tl])) que[tl]=l[i];
}
else que[++tl]=l[i];
}
while(hd<tl&&!isleft(getinter(que[tl-1],que[tl]),que[hd])) tl--;
rin(i,hd,tl) add_edge(x,que[i].id);
} std::queue<int> bfq;
inline void bfs(){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
while(!bfq.empty()) bfq.pop();
vis[s]=1,dis[s]=1,bfq.push(s);
while(!bfq.empty()){
int x=bfq.front();bfq.pop();
trav(i,x){
int ver=e[i].to;
if(vis[ver]) continue;
vis[ver]=1,dis[ver]=dis[x]+1;
if(ver==n+1) return;
bfq.push(ver);
}
}
} int main(){
int T=read();
while(T--){
s=0;
ecnt=0;memset(head,0,sizeof head);
memset(invalid,0,sizeof invalid);
n=read();
C=read(),R=read(),sx=read(),sy=read();
if(n==0){printf("0\n");continue;}
rin(i,1,n){
re[i].x=read(),re[i].y=read();
if(re[i].x>=C||re[i].y>=R) invalid[i]=1;
}
rin(i,1,n) if(!invalid[i]) solve(i);
rin(i,1,n) if(!invalid[i]) if(!s||dcmp(getlen(re[i]-(Po){sx,sy}),getlen(re[s]-(Po){sx,sy}))<0) s=i;
bfs();
printf("%d\n",dis[n+1]-1);
}
return 0;
}

[BZOJ3199][SDOI2013]escape:半平面交的更多相关文章

  1. 【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交

    4515: [Sdoi2016]游戏 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 304  Solved: 129[Submit][Status][ ...

  2. poj3335 半平面交

    题意:给出一多边形.判断多边形是否存在一点,使得多边形边界上的所有点都能看见该点. sol:在纸上随手画画就可以找出规律:按逆时针顺序连接所有点.然后找出这些line的半平面交. 题中给出的点已经按顺 ...

  3. POJ3525 半平面交

    题意:求某凸多边形内部离边界最远的点到边界的距离 首先介绍半平面.半平面交的概念: 半平面:对于一条有向直线,它的方向的左手侧就是它所划定的半平面范围.如图所示: 半平面交:多个半平面的交集.有点类似 ...

  4. POJ 3130 How I Mathematician Wonder What You Are! /POJ 3335 Rotating Scoreboard 初涉半平面交

    题意:逆时针给出N个点,求这个多边形是否有核. 思路:半平面交求多边形是否有核.模板题. 定义: 多边形核:多边形的核可以只是一个点,一条直线,但大多数情况下是一个区域(如果是一个区域则必为 ).核内 ...

  5. bzoj2618[Cqoi2006]凸多边形 半平面交

    这是一道半平面交的裸题,第一次写半平面交,就说一说我对半平面交的理解吧. 所谓半平面交,就是求一大堆二元一次不等式的交集,而每个二元一次不等式的解集都可以看成是在一条直线的上方或下方,联系直线的标准方 ...

  6. POJ 3384 Feng Shui 半平面交

    题目大意:一个人很信"Feng Shui",他要在房间里放两个圆形的地毯. 这两个地毯之间可以重叠,可是不能折叠,也不能伸到房间的外面.求这两个地毯可以覆盖的最大范围.并输出这两个 ...

  7. BZOJ2618[Cqoi2006]凸多边形——半平面交

    题目描述 逆时针给出n个凸多边形的顶点坐标,求它们交的面积.例如n=2时,两个凸多边形如下图: 则相交部分的面积为5.233. 输入 第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形.第 ...

  8. 洛谷P3222 [HNOI2012]射箭(计算几何,半平面交,双端队列)

    洛谷题目传送门 设抛物线方程为\(y=ax^2+bx(a<0,b>0)\),我们想要求出一组\(a,b\)使得它尽可能满足更多的要求.这个显然可以二分答案. 如何check当前的\(mid ...

  9. bzoj 4445 小凸想跑步 - 半平面交

    题目传送门 vjudge的快速通道 bzoj的快速通道 题目大意 问在一个凸多边形内找一个点,连接这个点和所有顶点,使得与0号顶点,1号顶点构成的三角形是最小的概率. 假设点的位置是$(x, y)$, ...

随机推荐

  1. MySQL的count(*)性能怎么样?

    对于count(主键id)来说,innodb引擎会遍历整张表,把每一行的id值都取出来,返回给server层,server层判断id值不为空,就按行累加 对于count(1)来说,innodb引擎遍历 ...

  2. (已实践)PLSQL本地还原Oracle数据库dmp文件

    这个方法很烂,导致重装Oracle时候处处出现问题,不建议使用这个方法,除非你以后不再用Oracle这个软件了,这个方法很烂,再评论一下. 第一,启动服务,(如果数据库处于启动状态,那么略过这一步) ...

  3. 第五周课程总结&试验报告(三

    实验三 String类的应用 实验目的 掌握类String类的使用: 学会使用JDK帮助文档: 实验内容 1.已知字符串:"this is a test of java".按要求执 ...

  4. Mybatis-学习笔记(4)1对1、1对多、多对多

    1.1对1 有2种方式对内嵌Bean设值: 1>关联查询就一条语句.使用association关键字,直接将嵌套对象的映射表的字段赋值内嵌对象. <association property ...

  5. C++中的const分析

    1,C 语言中的 const: 1,const 修饰的变量是只读的,本质还是变量: 1,C 语言中的 const 使变量具有只读属性: 2,const 只在编译期有用,在运行期无用: 3,const ...

  6. 【系统】win10锁屏后,护眼绿自动恢复解决

    针对自己电脑(其他人的不晓得),win10锁屏后,重新登录,护眼绿会自动恢复成白色,查询资料需要修改注册表两个地方: 1.计算机\HKEY_CURRENT_USER\Control Panel\Col ...

  7. Python list和tuple的相互转换?

    list转为tuple: temp_list = [1,2,3,4,5] 将temp_list进行强制转换:tuple(temp_list) 查看是否转换成功:print type(temp_list ...

  8. RabbitMQ交换器Exchange介绍与实践

    RabbitMQ交换器Exchange介绍与实践 RabbitMQ系列文章 RabbitMQ在Ubuntu上的环境搭建 深入了解RabbitMQ工作原理及简单使用 RabbitMQ交换器Exchang ...

  9. spring boot 枚举使用的坑2

    上一篇说到在枚举当在controller的方法做参数时的坑,解决方法是配置了一个converter,后来想想,如果不闲每次都加一个注解麻烦的话,可以在参数前面加一个注解,添加一个解析器应该也可以解决这 ...

  10. MFC- 网络编程

    一.MFC网络编程 a)CAsyncSocket用于异步非阻塞类,用UDP通信: b)CAsyncSocket的子类(派生类):Csocket同步阻塞类,用于TCP通信: c)通信前,必须调用AfxS ...