传送门

完全看不出这思路是怎么来的……

首先对于两个亲戚,他们监视范围的边界是他们连线的中垂线。那么对于一个亲戚来说它能监视的范围就是所有的中垂线形成的半平面交

然后如果某两个亲戚的监视范围有公共边,那么就在这两个亲戚之间连一条边,如果某个亲戚的监视范围和矩阵边界有公共边,那么就把这个亲戚和终点连边。然后以一开始监视的亲戚为起点,跑一遍最短路即可

//minamoto
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
using namespace std;
int read(){
int res,f=1;char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=10005;
int S,T,n,times,sx,sy,bx,by,no[N],m;
struct Graph{
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void clr(){tot=0;memset(head,0,sizeof(head));}
inline void add(int u,int v){e[++tot]={v,head[u]},head[u]=tot;}
int dis[N],q[N];bool vis[N];
int spfa(){
fp(i,1,n+1)dis[i]=inf,vis[i]=0;
int h=0,t=1;dis[S]=0,q[h]=S;
while(h!=t){
int u=q[h++];vis[u]=0;if(h==N)h-=N;
go(u)if(dis[v]>dis[u]+1){
dis[v]=dis[u]+1;
if(!vis[v]){
q[t++]=v,vis[v]=1;
if(t==N)t-=N;
}
}
}return dis[T];
}
}G;
struct node{double x,y;}p[N];
struct line{
node a,b;int id;double sl;
inline line(){}
inline line(node a,node b,int id):a(a),b(b),id(id){sl=atan2(b.y-a.y,b.x-a.x);}
}q[N],a[N],l[N];
inline node operator +(node a,node b){return {a.x+b.x,a.y+b.y};}
inline node operator -(node a,node b){return {a.x-b.x,a.y-b.y};}
inline double operator *(node a,node b){return a.x*b.y-a.y*b.x;}
inline bool operator <(line a,line b){return a.sl==b.sl?(a.b-a.a)*(b.a-a.a)<=0:a.sl<b.sl;}
node inter(line a,line b){
double k1,k2,t;
k1=(b.b-a.a)*(a.b-a.a);
k2=(a.b-a.a)*(b.a-a.a);
t=k2/(k1+k2);
return {b.a.x+t*(b.b.x-b.a.x),b.a.y+t*(b.b.y-b.a.y)};
}
inline bool jd(line a,line b,line c){node p=inter(a,b);return (p-c.a)*(c.b-c.a)>0;}
void hpi(int st){
int tot=0;sort(l+1,l+1+m);
fp(i,1,m)if(l[i].sl!=a[tot].sl)a[++tot]=l[i];
int h=1,t=0;q[++t]=a[1],q[++t]=a[2];
fp(i,3,tot){
while(h<t&&jd(q[t-1],q[t],a[i]))--t;
while(h<t&&jd(q[h+1],q[h],a[i]))++h;
q[++t]=a[i];
}
while(h<t&&jd(q[t-1],q[t],q[h]))--t;
while(h<t&&jd(q[h+1],q[h],q[t]))++h;
fp(i,h,t)G.add(st,q[i].id);
}
void clr(){G.clr(),memset(no,0,sizeof(no));}
double dis(node a,node b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
node rotate(node a){return {-a.y,a.x};}
node getmid(node a,node b){return {(a.x+b.x)/2,(a.y+b.y)/2};}
void init(int st){
l[1]=line({0,0},{sx,0},n+1),l[2]=line({sx,0},{sx,sy},n+1);
l[3]=line({sx,sy},{0,sy},n+1),l[4]=line({0,sy},{0,0},n+1);
m=4;
fp(i,1,n)if(i!=st&&!no[i]){
node mid=getmid(p[i],p[st]);
node v=rotate(p[i]-p[st]);
l[++m]=line(mid,mid+v,i);
}
}
void solve(){
clr(),n=read(),sx=read(),sy=read(),bx=read(),by=read();
node res={bx,by};
if(!n)return (void)(puts("0"));
T=n+1;int pos=0;double len=1e15;
fp(i,1,n){
p[i].x=read(),p[i].y=read();
if(p[i].x>sx||p[i].y>sy)no[i]=1;
double now=dis(p[i],res);
if(now<len)len=now,pos=i;
}S=pos;
fp(i,1,n)if(!no[i])init(i),hpi(i);
printf("%d\n",G.spfa());
}
int main(){
// freopen("testdata.in","r",stdin);
times=read();
while(times--)solve();
return 0;
}

P3297 [SDOI2013]逃考的更多相关文章

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

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

  2. luogu P3297 [SDOI2013]逃考

    传送门 gugugu 首先每个人管理的区域是一个多边形,并且整个矩形是被这样的多边形填满的.现在的问题是求一条经过多边形最少的路径到达边界,这个可以最短路. 现在的问题是建图,显然我们应该给相邻的多边 ...

  3. BZOJ3199 SDOI2013 逃考 半平面交、最短路

    传送门 如果我们对于每一个点能找到与其相邻的点(即不经过其他点监视范围能够直接到达其监视范围的点)和是否直接到达边界,就可以直接BFS求最短路求出答案. 所以当前最重要的问题是如何找到对于每一个点相邻 ...

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

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

  5. [JZOJ3297] 【SDOI2013】逃考

    题目 我发现我现在连题面都懒得复制粘贴了-- 题目大意 在一个矩形中有一堆点,这堆点按照以下规则将矩形瓜分成一堆块: 对于每个坐标,它属于离它最近的点的块. 一个人从某个坐标出发到矩形外面,求经过的最 ...

  6. 【JZOJ3297】【SDOI2013】逃考(escape)

    Mission 高考又来了,对于不认真读书的来讲真不是个好消息.为了小杨能在家里认真读书,他的亲戚决定驻扎在他的家里监督他学习,有爷爷奶奶.外公外婆.大舅.大嫂.阿姨-- 小杨实在是忍无可忍了,这种生 ...

  7. 2014秋C++第5周项目1參考-见识刚開始学习的人常见错误

    课程主页在http://blog.csdn.net/sxhelijian/article/details/39152703,实践要求见http://blog.csdn.net/sxhelijian/a ...

  8. C++常考面试题汇总

    c++面试题 一 用简洁的语言描述 c++ 在 c 语言的基础上开发的一种面向对象编程的语言: 应用广泛: 支持多种编程范式,面向对象编程,泛型编程,和过程化编程:广泛应用于系统开发,引擎开发:支持类 ...

  9. AWS的SysOps认证考试样题解析

    刚考过了AWS的developer认证,顺手做了一下SysOps的样题.以下是题目和答案. When working with Amazon RDS, by default AWS is respon ...

随机推荐

  1. git-github 提示Permission denied (publickey) (windows)

    这种绝大多数情况是由于公钥设置的问题. 1.生成公钥 参考地址:https://help.github.com/articles/generating-a-new-ssh-key-and-adding ...

  2. Qt——信号与槽用法总结(未完待续)

    1.设计模式中信号与槽编辑选项卡 2.右键组件,转到槽,写函数 void LoginDialog::on_loginBtn_clicked() { accept(); } 3.信号与槽编辑模式 按下F ...

  3. 找出消耗CPU最高的进程对应的SQL语句

    COLUMN PID FORMAT 999COLUMN S_# FORMAT 999COLUMN USERNAME FORMAT A9 HEADING "ORA USER"COLU ...

  4. 第五章、 Linux 常用網路指令

    http://linux.vbird.org/linux_server/0140networkcommand.php     第五章. Linux 常用網路指令 切換解析度為 800x600 最近更新 ...

  5. BZOJ 1225: [HNOI2001] 求正整数 高精度+搜索+质数

    题意:给定n求,有n个因子的最小正整数. 题解:水题,zcr都会,我就不说什么了. 因数个数球求法应该知道,将m分解质因数,然后发现 a1^p1*a2^p2....an^pn这样一个式子, (1+p1 ...

  6. SOJ 3531_Number Pyramids

    [题意]给定一个数top及最底层元素个数n,构成一个以给top为塔尖,层数为n的如杨辉三角的金字塔,求有多少种 [分析]最终种数其实只与最底层的n个数的组合数有关,上层的每个都数是由最底层数相加得来 ...

  7. Ubuntu 16.04无损分区大小调整工具Gparted

    安装: sudo apt-get install gparted 使用: 注意: 这款软件可以调整分区大小,且支持无损,但是对于/根目录的分区无法调整,但是它提供ISO工具,可以启动后进行调整. 下载 ...

  8. 消息队列RabbitMQ使用教程收集

    学习应该要系统,最好的方式是看书. RabbitMQ最权威的教程应该参考官方文档. 下面是收集的一些教程: 官方: https://www.rabbitmq.com/getstarted.html h ...

  9. MongoDB小结02 - 配置、启动MongoDB

    下载MongoDB 第一步:登上MongoDB官网,找到自己的适合的版本下载 第二步:解压(免安装),改名mongodb(举例命名,可以任个人喜好),放在你喜欢的位置(任喜好) 第三步:通过命令行: ...

  10. socker地址API

    大端字节序是指一个整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处.小端字节序是指整数的高位字节存储在内存的高地址处,低位字节则存储在内存的低地址处. 现代pc大多采用小端字节序,故小 ...