传送门


如果我们对于每一个点能找到与其相邻的点(即不经过其他点监视范围能够直接到达其监视范围的点)和是否直接到达边界,就可以直接BFS求最短路求出答案。

所以当前最重要的问题是如何找到对于每一个点相邻的点。

如果你知道泰森多边形,你就可以发现所有点的监视范围刚好对应这些点在这个矩形里的泰森多边形。

因为两个点监视范围的分界线一定在这两个点对应线段的中垂线上,所以将当前点到所有点的中垂线拿出来跑一遍半平面交,如果某个点与当前点的中垂线在半平面交中,那么这两个点就相邻。

还需要知道对于某个点能否不经过其他点的监视范围到达边界,这只需要在求半平面交的时候将矩形的四边也加上就可以了。

时间复杂度\(O(TN^2logN)\),可能需要轻微的常数优化。

写计算几何的时候务必注意细节,否则可能因为把\(xy\)坐标打反等小错误调很久QAQ

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
//This code is written by Itst
using namespace std; #define ld long double
const ld eps = 1e-12;
bool cmp(ld a , ld b){return a - eps < b && a + eps > b;} struct comp{
ld x , y , dir;
comp(ld _x = 0 , ld _y = 0) : x(_x) , y(_y){dir = atan2(y , x);}
comp operator +(comp a){return comp(x + a.x , y + a.y);}
comp operator -(comp a){return comp(x - a.x , y - a.y);}
comp operator *(ld a){return comp(x * a , y * a);}
ld operator *(comp a){return x * a.x + y * a.y;}
ld operator %(comp a){return x * a.y - y * a.x;}
bool operator <(const comp a)const{return dir < a.dir;}
bool operator ==(const comp a)const{return cmp(dir , a.dir);}
}now[607]; struct line{
comp pos , dir;
int ind;
line(comp a = comp(0,0) , comp b = comp(0,0) , int id = 0) : pos(a) , dir(b) , ind(id){}
bool operator <(const line a)const{return dir < a.dir || dir == a.dir && ((comp)a.pos - pos) % dir > 0;}
}cur[607]; struct Edge{
int end , upEd;
}Ed[370007];
int head[607] , que[607];
int cntEd , N , X0 , Y0 , X1 , Y1 , hd , tl , T;
bool mrk[607] , vis[607]; inline void addEd(int a , int b){
Ed[++cntEd] = (Edge){b , head[a]};
head[a] = cntEd;
} comp rot(comp a){
ld Cos = 0 , Sin = 1;
return comp(a.x * Cos - a.y * Sin , a.x * Sin + a.y * Cos);
} comp intersect(line a , line b){
ld t = (b.dir % (a.pos - b.pos)) / (a.dir % b.dir);
return a.pos + a.dir * t;
} bool chk(line a , line b , line c){
return (intersect(a , b) - c.pos) % c.dir > 0;
} void create(int x){
int cnt = 0;
cur[++cnt] = line(comp(0 , 0) , comp(1 , 0));
cur[++cnt] = line(comp(X1 , 0) , comp(0 , 1));
cur[++cnt] = line(comp(X1 , Y1) , comp(-1 , 0));
cur[++cnt] = line(comp(0 , Y1) , comp(0 , -1));
for(int i = 1 ; i <= N ; ++i)
if(i != x)
cur[++cnt] = line((now[i] + now[x]) * 0.5 , rot(now[i] - now[x]) , i);
sort(cur + 1 , cur + cnt + 1);
hd = tl = que[1] = 1;
for(int i = 2 ; i <= cnt ; ++i){
if(cur[i].dir == cur[i - 1].dir) continue;
while(hd < tl && chk(cur[que[tl]] , cur[que[tl - 1]] , cur[i]))
--tl;
while(hd < tl && chk(cur[que[hd]] , cur[que[hd + 1]] , cur[i]))
++hd;
que[++tl] = i;
}
while(hd < tl && chk(cur[que[tl]] , cur[que[tl - 1]] , cur[que[hd]]))
--tl;
while(hd <= tl){
if(!cur[que[hd]].ind) mrk[x] = 1;
else addEd(cur[que[hd]].ind , x);
++hd;
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
ios::sync_with_stdio(0);
for(cin >> T ; T ; --T){
cntEd = 0;
memset(mrk , 0 , sizeof(mrk));
memset(vis , 0 , sizeof(vis));
memset(head , 0 , sizeof(head));
cin >> N >> X1 >> Y1 >> X0 >> Y0;
if(!N){cout << "0\n"; continue;}
for(int i = 1 ; i <= N ; ++i)
cin >> now[i].x >> now[i].y;
for(int i = 1 ; i <= N ; ++i)
create(i);
queue < int > q;
ld minDis = 1e18;
int minInd = 0;
for(int i = 1 ; i <= N ; ++i){
ld dis = sqrt((now[i].x - X0) * (now[i].x - X0) + (now[i].y - Y0) * (now[i].y - Y0));
if(dis < minDis){minDis = dis; minInd = i;}
}
vis[minInd] = 1;
q.push(minInd);
bool f = 0;
for(int i = 1 ; !f ; ++i){
for(int j = q.size() ; !f && j ; --j){
int t = q.front(); q.pop();
if(mrk[t]){f = 1; continue;}
for(int i = head[t] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]){
vis[Ed[i].end] = 1;
q.push(Ed[i].end);
}
}
if(f) cout << i << endl;
}
}
return 0;
}

BZOJ3199 SDOI2013 逃考 半平面交、最短路的更多相关文章

  1. [BZOJ3199][SDOI2013]escape:半平面交

    分析 好像叫V图什么的. 容易发现,对于每个点,其监视的范围就是这个点与其它所有点的垂直平分线分割平面后的半平面交.由于数据范围很小,所以我们可以直接枚举每个点,使用双端队列求出其监视的范围.若两个点 ...

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

    把每个人的监视范围看成点,相邻的两个监视范围连边,那么跑一遍最短路就可以了(事实上边权都为1可以直接bfs).显然存在最优路线没有某个时刻同时被多于两人监视,要到达另一个区域的话完全可以经过分界线而不 ...

  3. 洛谷 P3297 [SDOI2013]逃考 解题报告

    P3297 [SDOI2013]逃考 题意 给一个平面矩形,里面有一些有标号点,有一个是人物点,人物点会被最近的其他点控制,人物点要走出矩形,求人物点最少被几个点控制过. 保证一开始只被一个点控制,没 ...

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

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

  5. poj3335 半平面交

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

  6. POJ3525 半平面交

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

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

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

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

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

  9. POJ 3384 Feng Shui 半平面交

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

随机推荐

  1. Android性能优化问题总结

    性能优化这块,分为UI性能优化.内存优化.数据库优化.网络优化.耗电优化等等.可以从1.如何发现问题,2.怎么解决问题,3.解决效果对比,这几个方面去描述.举个简单例子——UI优化,可以从 UI出现什 ...

  2. Android--手势及触摸事件的注意点(一)

    实现onInterceptTouchEvent方法可以用来拦截父ViewGroup传递下来的所有触屏事件,可以将所有触屏事件交由此ViewGroup自身的onTouchEvent来处理,也可以继续传递 ...

  3. JAVA设计模式——代理(动态代理)

    传送门:JAVA设计模式——代理(静态代理) 序言: 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring ...

  4. MySQL优化技巧【持续更新】

    前言 应用程序或web网页有时慢的像蜗牛爬似的,可能是网络原因,可能是系统架构原因,还有可能是数据库原因.那么如何提高数据库SQL语句执行速度呢?下面是积累的一些优化技巧,望对君有用. 正文 1.比较 ...

  5. SQL Server 2005 sp_send_dbmail出现Internal error at FormatRowset (Reason: Not enough storage is available to complete this operation)

    案例环境: 操作系统: Windows 2003 SE 32bit(SP2) 数据库版本:Microsoft SQL Server 2005 - 9.00.5069.00 (Intel X86) Au ...

  6. NUMA导致的Oracle性能问题

    背景简介: Oracle版本:11.2.0.4 OS 版本:OEL5.8 在一次Oracle的Dataguard正常switchover过程中,遇到了一个极其诡异的问题,一条主业务的SQL语句在新主库 ...

  7. c/c++ 标准库 set 自定义关键字类型与比较函数

    标准库 set 自定义关键字类型与比较函数 问题:哪些类型可以作为标准库set的关键字类型呢??? 答案: 1,任意类型,但是需要额外提供能够比较这种类型的比较函数. 2,这种类型实现了 < 操 ...

  8. 三星笔记本进入BIOS后找不到U盘启动项/快速启动键F12没有反应

    分析:BIOS开启了 Fast Bios Mode 解决方法: 开机按F2进入BIOS设置,选择Advanced菜单下Fast Bios Mode,设置为 Disabled,按F10键保存退出,重启时 ...

  9. Python: datetime 转换

    Directive Meaning Example Notes %a Weekday as locale’s abbreviated name. Sun, Mon, …, Sat (en_US); S ...

  10. 如何用Jupyter notebook打开本地数据集

    首先打开本地Jupyter notebook,出现类似页面并进入网页端Home. 网页端界面类似如下: 需要注意的是,Jupyter notebook只能打开当前目录下的数据集,如csv,所以需要使用 ...