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

  把每个人的监视范围看成点,相邻的两个监视范围连边,那么跑一遍最短路就可以了(事实上边权都为1可以直接bfs)。显然最优的话不会有某个时刻同时被多人监视,要跨过去的话完全可以经过分界线而不是交点。

  现在问题是怎么求出哪些监视范围相邻。考虑对于某个人的监视范围求出所有与它相邻的。两个监视范围的公共边是这两个人连线的中垂线,把这些线画出来可以发现求个半平面交就好了。注意线要求在矩形范围内。如果直线在半平面交中只剩下一个点应该去掉。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 610
#define vector dot
int T,n,p[N],d[N],queue[N],cnt;
bool flag[N];
const double eps=1E-10;
struct data{int to,nxt;
}edge[N*N];
struct dot
{
    double x,y;
    vector operator +(const vector&a) const
    {
        return (vector){x+a.x,y+a.y};
    }
    vector operator -(const vector&a) const
    {
        return (vector){x-a.x,y-a.y};
    }
    double operator *(const vector&a) const
    {
        return x*a.y-y*a.x;
    }
    vector operator *(const double a) const
    {
        return (vector){a*x,a*y};
    }
    double len()
    {
        return sqrt(x*x+y*y);
    }
    vector rotate()
    {
        return (vector){-y,x};
    }
}a[N],P[N];
struct line
{
    dot a;vector p;int i;
    bool operator <(const line&a) const
    {
        return atan2(p.x,p.y)>atan2(a.p.x,a.p.y);
    }
}q[N],Q[N];
void addedge(int x,int y){cnt++;edge[cnt].to=y,edge[cnt].nxt=p[x],p[x]=cnt;}
bool onright(line x,dot y)
{
    return (y-x.a)*x.p>=0;
}
dot cross(line x,line y)
{
    return y.a+y.p*(x.p*(x.a-y.a)/(x.p*y.p));
}
int bfs(int S)
{
    memset(d,42,sizeof(d));
    int head=0,tail=1;queue[1]=S;d[S]=0;
    do
    {
        int x=queue[++head];
        for (int i=p[x];i;i=edge[i].nxt)
        if (d[x]+1<d[edge[i].to])
        {
            d[edge[i].to]=d[x]+1;
            queue[++tail]=edge[i].to;
            if (!edge[i].to) return d[edge[i].to];
        }
    }while (head<tail);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("3297.in","r",stdin);
    freopen("3297.out","w",stdout);
    const char LL[]="%I64d";
#else
    const char LL[]="%lld";
#endif
    T=read();
    while (T--)
    {
        n=read();
        int r=read(),c=read();
        dot s;s.x=read(),s.y=read();
        for (int i=1;i<=n;i++)
        a[i].x=read(),a[i].y=read();
        int S;
        double dis=(a[1]-s).len();
        for (int i=2;i<=n;i++) dis=min(dis,(a[i]-s).len());
        for (int i=1;i<=n;i++) if (fabs(dis-(a[i]-s).len())<eps) S=i;
        cnt=0;
        memset(p,0,sizeof(p));
        for (int j=1;j<=n;j++)
        {
            int t=0;
            for (int i=1;i<=n;i++)
            if (i!=j) q[++t]=(line){(a[i]+a[j])*0.5,(a[i]-a[j]).rotate(),i};
            q[++t]=(line){(dot){0,0},(vector){1,0},0};
            q[++t]=(line){(dot){r,0},(vector){0,1},0};
            q[++t]=(line){(dot){r,c},(vector){-1,0},0};
            q[++t]=(line){(dot){0,c},(vector){0,-1},0};
            sort(q+1,q+t+1);
            int head=1,tail=1;Q[1]=q[1];
            for (int i=2;i<=t;i++)
            {
                while (head<tail&&onright(q[i],P[tail])) tail--;
                while (head<tail&&onright(q[i],P[head+1])) head++;
                Q[++tail]=q[i];
                if (fabs(Q[tail-1].p*Q[tail].p)<eps)
                {
                    tail--;
                    if (onright(q[i],Q[tail].a)) Q[tail]=q[i];
                }
                if (head<tail) P[tail]=cross(Q[tail],Q[tail-1]);
            }
            while (head<tail&&onright(Q[head],P[tail])) tail--;
            P[head]=cross(Q[head],Q[tail]);
            for (int i=head;i<=tail;i++) addedge(j,Q[i].i);
        }
        printf("%d\n",bfs(S));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Gloid/p/9418277.html

时间: 2024-10-09 13:20:25

Luogu3297 SDOI2013逃考(半平面交+最短路)的相关文章

[半平面交][最短路]JZOJ 3297 【SDOI2013】逃考

Description 高考又来了,对于不认真读书的来讲真不是个好消息.为了小杨能在家里认真读书,他的亲戚决定驻扎在他的家里监督他学习,有爷爷奶奶.外公外婆.大舅.大嫂.阿姨……小杨实在是忍无可忍了,这种生活跟监狱有什么区别!为了他亲爱的小红,为了他的dota,他决定越狱!假设小杨的家是个n*m 的矩阵,左下角坐标为(0,0),右上角坐标为(x1,y1).小杨有n 个亲戚,驻扎在矩阵里(位置不同,且不在矩阵的边上).小杨家里的每个地方都被亲戚监控着,而且只被距离最近的亲戚监控:也就是说假设小杨所

P3297 [SDOI2013]逃考

题意 两个亲戚间的范围的分界线必定为两者连线的中垂线,因此我们用半平面交\(O(n^2\log n)\)求出每个人的范围,之后相邻的两个范围连边跑最短路即可. 注意特判\(n=0\)的情况. code: #include<bits/stdc++.h> using namespace std; const int maxn=610; const double eps=1e-8; const double inf=1e12; const double Pi=acos(-1.0); int T,n,

POJ 2451 nlog(n)半平面交裸题。

前言       最近学习C#,不过好在当初考计算机二级学习过C++,刚上手没有对C#感到很恐惧.C#视频也看了几天 了,总感觉不总结一下心里没底,现在跟着我从头走进C#之旅吧.     C#是以后总面向对象的编程语言(OOP),C#是从C和C++派生出来的,主要用于开发可以运行在.NET平台 上的应用程序.随着.NET的发展,C#语言简单.现代.面向对象和类型安全显示了一定的优势.     下面我就介绍一些初学者不太理解的一些东西.   C#有以下突出的特点       (1)语法简洁.不允许

LA 2218 (半平面交) Triathlon

题意: 有n个选手,铁人三项有连续的三段,对于每段场地选手i分别以vi, ui 和 wi匀速通过. 对于每个选手,问能否通过调整每种赛道的长度使得他成为冠军(不能并列). 分析: 粗一看,这不像一道计算几何的题目. 假设赛道总长度是1,第一段长x,第二段长y,第三段则是1-x-y 那么可以计算出每个选手完成比赛的时间Ti 对于选手i,若要成为冠军则有Ti < Tj (i ≠ j) 于是就有n-1个不等式,每个不等式都代表一个半平面. 在加上x>0, y>0, 1-x-y>0 这三个

POJ3525-Most Distant Point from the Sea(二分+半平面交)

Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3955   Accepted: 1847   Special Judge Description The main land of Japan called Honshu is an island surrounded by the sea. In such an island, it is natural t

bzoj 1007 水平可见直线 半平面交稀里糊涂的过了...

题意:按y=Ax+B的形式给出n(<=50000)条直线,求从y值为无穷大的地方向下看能看到的直线编号 一看到题目就想到半平面交,以每条直线的上方为一个半平面,求半平面的交,交集中存在的直线就是能看到的直线 但是写出来之后发现样例都过不了... 对于样例,如果允许半平面在边界处重叠那么答案是1,2,3,如果不允许只有1.. 然后抱着试一试的心理交上去了,结果竟然直接AC了.. 后来看题解只需要考虑交点x坐标.. bzoj 1007 水平可见直线 半平面交稀里糊涂的过了...,布布扣,bubuko

POJ 2540 半平面交求可行区域面积

Hotter Colder Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2343   Accepted: 981 Description The children's game Hotter Colder is played as follows. Player A leaves the room while player B hides an object somewhere in the room. Player

poj 3525 Most Distant Point from the Sea 半平面交 + 二分

题目来源: http://poj.org/problem?id=3525 分析: 题意:给定一个凸多边形,求多边形中距离边界最远的点到边界的距离. 思路 : 每次将凸多边形每条边往里平移d,判断是否存在核:二分d即可. 多边形边上的点(x , y)往里平移d 后的 坐标: s , e  为向量的 起点和终点, len 为起点和终点的距离, h 为平移的距离 x' = x + dx y' = y + dy dx = ( s.y - e.y ) / len * h ,( 原理 是 利用 三角形的相似

UVALive 4992 Jungle Outpost(半平面交)

题意:给你n个塔(点)形成一个顺时针的凸包,敌人可以摧毁任何塔,摧毁后剩下的塔再组成凸包 在开始的凸包内选一点为主塔,保证敌人摧毁尽量多塔时主塔都还在现在的凸包内,求出最多摧毁的塔 题解:这题关键就是选的主塔在不同的地方,敌人就会摧毁不同的塔来让你的主塔暴露 因此这样想,找出敌人摧毁不同的塔后形成的所有不同的凸包,再求出所有凸包的交就好 具体就是,首先枚举摧毁塔的个数k,再把摧毁任意k个塔所形成的所有不同的凸包求一个交,如果为空就代表了摧毁k个塔一定可以保证无论主塔在哪儿都可以暴露(关键) 而所