【JZOJ3297】【SDOI2013】逃考(escape)
Mission
高考又来了,对于不认真读书的来讲真不是个好消息。为了小杨能在家里认真读书,他的亲戚决定驻扎在他的家里监督他学习,有爷爷奶奶、外公外婆、大舅、大嫂、阿姨……
小杨实在是忍无可忍了,这种生活跟监狱有什么区别!为了他亲爱的小红,为了他的dota,他决定越狱!
假设小杨的家是个n*m 的矩阵,左下角坐标为(0,0),右上角坐标为(x1,y1)。小杨有n 个亲戚,驻扎在矩阵里(位置不同,且不在矩阵的边上)。小杨家里的每个地方都被亲戚监控着,而且只被距离最近的亲戚监控:
也就是说假设小杨所在的位置是(3,3),亲戚A 在(3,0),A 距离小杨距离是3;亲戚B 在(6,7),则B 距离小杨距离是5。距离A < 距离B,所以(3,3)位置由A 监控。
如果“最近距离”出现同时有几个亲戚,那么那个位置同时被那几个亲戚监控。
给出小杨的坐标(x0,y0)。因为被发现的人数越少,越狱成功的机会越大,所以小杨需要你设计一条越狱路线到达矩形的边上,且被发现的人数最少。
Ps:小杨做的方向是任意的,也就是说路线上的任意位置只需要是实数。
保证一开始小杨只被一个亲戚监控着。
n<=600
Solution
显然,每个点与其他点连线的中垂线形成的半平面求交,就是这个点的监视范围。
然后最短路即可。
Code
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<string.h>
#define ll long long
#define db double
using namespace std;
const char* fin="ex3297.in";
const char* fout="ex3297.out";
const db eps=10e-10;
const int inf=0x7fffffff;
const int maxn=607,maxm=maxn*maxn;
bool equ(db v,db x){return fabs(v-x)<=eps;}
int sgn(db x){return equ(x,0.0)?0:(x<0?-1:1);}
struct P{
db x,y;
P(db _x=0,db _y=0){x=_x;y=_y;}
P operator +(P b){return P(x+b.x,y+b.y);}
P operator -(P b){return P(x-b.x,y-b.y);}
P operator *(db b){return P(x*b,y*b);}
P per(){return P(y,-x);}
db operator ^(P b){return x*b.y-y*b.x;}
db arg(){return atan2(y,x);}
void read(){scanf("%lf",&x);scanf("%lf",&y);}
}a[maxn];
struct L{
P p,v;
int id;
L(){}
L(P _p,P _v,int _id=0){p=_p;v=_v;id=_id;}
db arg(){return v.arg();}
P operator &(L b){return b.p+b.v*((v^(p-b.p))/(v^b.v));}
}b[maxn],c[maxn];
int num;
bool cmp(L a,L b){return a.arg()<b.arg();}
bool in(P p,L l){return sgn((p-l.p)^l.v)>=0;}
P mid(P a,P b){return P((a.x+b.x)/2.0,(a.y+b.y)/2.0);}
int n,t,i,j,k,X,Y,sx,sy,st,tot,head,tail;
int fi[maxn],ne[maxm],la[maxm],va[maxm];
int B[maxn*10],dis[maxn];
bool bz[maxn];
void add_line(int a,int b,int c){
tot++;
ne[tot]=fi[a];
la[tot]=b;
va[tot]=c;
fi[a]=tot;
}
void add(int v,int u){
if (dis[v]>u){
dis[v]=u;
if (!bz[v]){
B[++tail]=v;
bz[v]=true;
}
}
}
void spfa(int v){
int i,j,k;
memset(dis,127,sizeof(dis));
head=tail=0;
add(v,0);
while (head++<tail){
for (k=fi[B[head]];k;k=ne[k])
add(la[k],dis[B[head]]+va[k]);
bz[B[head]]=false;
}
}
int main(){
scanf("%d",&t);
while (t--){
scanf("%d",&n);
scanf("%d%d%d%d",&X,&Y,&sx,&sy);
tot=0;
st=0;
P stp(sx,sy);
memset(fi,0,sizeof(fi));
for (i=1;i<=n;i++) a[i].read();
for (i=1;i<=n;i++){
num=0;
for (j=1;j<=n;j++){
if (i==j) continue;
b[++num]=L(mid(a[i],a[j]),(a[j]-a[i]).per(),j);
}
b[++num]=L(P(0,0),P(0,1),0);
b[++num]=L(P(0,Y),P(1,0),0);
b[++num]=L(P(X,Y),P(0,-1),0);
b[++num]=L(P(X,0),P(-1,0),0);
sort(b+1,b+num+1,cmp);
int N=0;
for (j=1;j<=num;j++){
if (!N) b[++N]=b[j];
else if (!equ(b[N].arg(),b[j].arg())) b[++N]=b[j];
else if (in(b[j].p,b[N])) b[N]=b[j];
}
num=N;
int head=1,tail=2;
bool noans=false;
c[1]=b[1],c[2]=b[2];
for (j=3;j<=num;j++){
while (head<tail && !in(c[tail]&c[tail-1],b[j])) tail--;
while (head<tail && !in(c[head]&c[head+1],b[j])) head++;
if (head==tail && sgn(c[head].v^b[j].v)<=0){noans=true;break;}
c[++tail]=b[j];
}
if (noans) continue;
while (head<tail && !in(c[tail]&c[tail-1],c[head])) tail--;
for (j=head;j<=tail;j++) add_line(i,c[j].id,1);
if (!st){
bool ST=true;
for (j=head;j<=tail;j++)
if (!in(stp,c[j])){
ST=false;
break;
}
if (ST) st=i;
}
}
spfa(st);
printf("%d\n",dis[0]);
}
return 0;
}
Warning
1.半平面交的流程
1)加入半平面以及四个特殊的边界半平面;
2)按半平面的极角排序,极角相同的半平面取较内侧的一个;
3)利用双端队列求出半平面交,头尾都要检查交点是否在新加入的半平面内;
注意:判断无解(队列中只剩一个半平面)
4)队列尾交点是否在头半平面中
【JZOJ3297】【SDOI2013】逃考(escape)的更多相关文章
- 洛谷 P3297 [SDOI2013]逃考 解题报告
P3297 [SDOI2013]逃考 题意 给一个平面矩形,里面有一些有标号点,有一个是人物点,人物点会被最近的其他点控制,人物点要走出矩形,求人物点最少被几个点控制过. 保证一开始只被一个点控制,没 ...
- BZOJ3199 SDOI2013 逃考 半平面交、最短路
传送门 如果我们对于每一个点能找到与其相邻的点(即不经过其他点监视范围能够直接到达其监视范围的点)和是否直接到达边界,就可以直接BFS求最短路求出答案. 所以当前最重要的问题是如何找到对于每一个点相邻 ...
- luogu P3297 [SDOI2013]逃考
传送门 gugugu 首先每个人管理的区域是一个多边形,并且整个矩形是被这样的多边形填满的.现在的问题是求一条经过多边形最少的路径到达边界,这个可以最短路. 现在的问题是建图,显然我们应该给相邻的多边 ...
- Luogu3297 SDOI2013逃考(半平面交+最短路)
把每个人的监视范围看成点,相邻的两个监视范围连边,那么跑一遍最短路就可以了(事实上边权都为1可以直接bfs).显然存在最优路线没有某个时刻同时被多于两人监视,要到达另一个区域的话完全可以经过分界线而不 ...
- P3297 [SDOI2013]逃考
传送门 完全看不出这思路是怎么来的-- 首先对于两个亲戚,他们监视范围的边界是他们连线的中垂线.那么对于一个亲戚来说它能监视的范围就是所有的中垂线形成的半平面交 然后如果某两个亲戚的监视范围有公共边, ...
- [JZOJ3297] 【SDOI2013】逃考
题目 我发现我现在连题面都懒得复制粘贴了-- 题目大意 在一个矩形中有一堆点,这堆点按照以下规则将矩形瓜分成一堆块: 对于每个坐标,它属于离它最近的点的块. 一个人从某个坐标出发到矩形外面,求经过的最 ...
- bzoj3199 [Sdoi2013]escape
这题真tm是醉了. 就是对于每个亲戚,利用其它的亲戚对他半平面交求出其控制的范围,然后随便跑个最短路就行了 n=0卡了我一下午////// #include <cstdio> #inclu ...
- [BZOJ3199][SDOI2013]escape:半平面交
分析 好像叫V图什么的. 容易发现,对于每个点,其监视的范围就是这个点与其它所有点的垂直平分线分割平面后的半平面交.由于数据范围很小,所以我们可以直接枚举每个点,使用双端队列求出其监视的范围.若两个点 ...
- ACM: Gym 101047E Escape from Ayutthaya - BFS
Gym 101047E Escape from Ayutthaya Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I6 ...
随机推荐
- 【neo4j】neo4j Desktop1.1.9,windows 安装
一.neo4j 介绍 Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储 ...
- MathType插件安装
1 安装包下载 版本号:7.4 下载 提取码:fxma 2 安装方法 用安装包内的Key激活即可.软件激活后不能升级. 注意:必须断网或者加入防火墙阻止联网使用! 3 可能遇到的问题 当安装完Math ...
- Leetcode513. Find Bottom Left Tree Value找树左下角的值
给定一个二叉树,在树的最后一行找到最左边的值. 示例 1: 输入: 2 / \ 1 3 输出: 1 示例 2: 输入: 1 / \ 2 3 / / \ 4 5 6 / 7 输出: 7 注意: 您可以假 ...
- [转]浅谈C#中常见的委托
一提到委托,浮现在我们脑海中的大概是听的最多的就是类似C++的函数指针吧,呵呵,至少我的第一个反应是这样的. 关于委托的定义和使用,已经有诸多的人讲解过,并且讲解细致入微,尤其是张子阳的那一篇.我就不 ...
- leetcode 1078 Occurrences After Bigram
lc1078 Occurrences After Bigram trim().split()将原字符串转换成words数组 依次匹配first和second,若两者都能匹配上,则下一个单词为third ...
- HZOI20190722 B visit 组合数+CRT合并
题目:https://www.cnblogs.com/Juve/articles/11226266.html solution: 30%:dp 设dp[k][i][j]表示经过k时间,在(i,j)的方 ...
- 写js过程中遇到的一个bug
<div class="func_Div" id="xxcx"><span>信息查询</span> ...
- Jeecms之查询实现
现有一需求如下: 按时间段查询及留言状态(已回复,未回复,已审批)来查询留言. 当时的想法是这样子的,首先要把查询的条件通过页面传递到后台.于是在后台管理中找看有没有类似的功能,费了半 ...
- PAT甲级——A1016 Phone Bills
A long-distance telephone company charges its customers by the following rules: Making a long-distan ...
- goland快捷键使用
查找替换: 格式化代码块:ctrl+alt+L将选中的行自动对齐:ctrl+alt+I优化没必要的imports:ctrl+alt+O展开代码块:ctrl+“+”展开文件中所有代码块:ctrl+shi ...