题目描述

致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。我们将H村抽象为一维的轮廓。如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长希望建造的塔高度尽可能小。请你写一个程序,帮助dadzhi村长计算塔的最小高度。

输入

第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1 ~ yn。

输出

仅包含一个实数,为塔的最小高度,精确到小数点后三位。

样例输入

【输入样例一】
6
1 2 4 5 6 7
1 2 2 4 2 1
【输入样例二】
4
10 20 49 59
0 10 10 0

样例输出

【输出样例一】
1.000
【输出样例二】
14.500


题解

半平面交

首先由于要看到所有点,因此选择的塔顶要在所有直线之上。因此求所有直线的上半平面的半平面交即为塔顶的范围。

由于要让塔的高度尽量小,因此塔顶的位置一定在半平面交下半部分的边上。

因此对于一个x,塔的高度就是 该点半平面交部分的高度-该点山的高度 。由于这两部分都是折线,作差也是折线。折线的最值只在拐点处取到,因此只需要枚举拐点位置即可。

细节超多又卡精。。。半平面交只能求封闭的凸多边形,因此需要在左、上、右各添加辅助线;辅助线不能影响半平面的范围,因此需要在山的左右端点处添加;辅助线的斜率不能是inf,因此不能与x轴垂直。

具体还是看代码吧。

时间复杂度 $O(n\log n)$

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 310
#define eps 1e-9
using namespace std;
typedef long double ld;
struct point
{
ld x , y;
point() {}
point(ld a , ld b) {x = a , y = b;}
point operator+(const point &a)const {return point(x + a.x , y + a.y);}
point operator-(const point &a)const {return point(x - a.x , y - a.y);}
point operator*(const ld &a)const {return point(x * a , y * a);}
bool operator<(const point &a)const {return x < a.x;}
}p[N] , c[N];
struct line
{
point p , v;
ld ang;
}a[N] , q[N];
inline ld cross(point a , point b) {return a.x * b.y - a.y * b.x;}
inline bool left(line a , point b) {return cross(a.v , b - a.p) > eps;}
inline point inter(line a , line b)
{
point u = a.p - b.p;
ld tmp = cross(b.v , u) / cross(a.v , b.v);
return a.p + a.v * tmp;
}
bool cmp(const line &a , const line &b)
{
return fabs(a.ang - b.ang) < eps ? left(a , b.p) : a.ang < b.ang;
}
int main()
{
int n , i , l = 1 , r = 1 , t , tot = 1;
ld ans = 1e20;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%Lf" , &p[i].x);
for(i = 1 ; i <= n ; i ++ ) scanf("%Lf" , &p[i].y);
for(i = 1 ; i < n ; i ++ ) a[i].p = p[i] , a[i].v = p[i] - p[i + 1] , a[i].ang = atan2(a[i].v.y , a[i].v.x);
a[n].p = point(0 , 1e20) , a[n].v = point(1 , 0) , a[n].ang = 0;
a[n + 1].p = point(p[1].x , p[1].y) , a[n + 1].v = point(-1e-10 , 1) , a[n + 1].ang = atan2(1 , 0);
a[n + 2].p = point(p[n].x , p[n].y) , a[n + 2].v = point(1e-10 , -1) , a[n + 2].ang = atan2(-1 , 0);
sort(a + 1 , a + n + 3 , cmp);
for(i = 2 ; i <= n + 2 ; i ++ )
if(fabs(a[i].ang - a[i - 1].ang) > eps)
a[++tot] = a[i];
q[1] = a[1];
for(i = 2 ; i <= tot ; i ++ )
{
while(l < r && left(a[i] , c[r - 1])) r -- ;
while(l < r && left(a[i] , c[l])) l ++ ;
q[++r] = a[i];
if(l < r) c[r - 1] = inter(q[r - 1] , q[r]);
}
while(l < r && left(q[l] , c[r - 1])) r -- ;
c[r] = inter(q[r] , q[l]);
sort(c + l , c + r + 1);
for(i = 1 , t = l ; i <= n ; i ++ )
{
while(t < r && c[t + 1] < p[i]) t ++ ;
ans = min(ans , (p[i].x - c[t].x) * (c[t + 1].y - c[t].y) / (c[t + 1].x - c[t].x) + c[t].y - p[i].y);
}
for(i = l , t = 1 ; i <= r ; i ++ )
{
if(c[i] < p[1] || p[n] < c[i]) continue;
while(t < n && p[t + 1] < c[i]) t ++ ;
ans = min(ans , c[i].y - (c[i].x - p[t].x) * (p[t + 1].y - p[t].y) / (p[t + 1].x - p[t].x) - p[t].y);
}
printf("%.3Lf\n" , ans);
return 0;
}

【bzoj1038】瞭望塔 半平面交的更多相关文章

  1. 【BZOJ1038】[ZJOI2008]瞭望塔 半平面交

    [BZOJ1038][ZJOI2008]瞭望塔 Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如 ...

  2. [日常摸鱼]bzoj1038[ZJOI2008]瞭望塔-半平面交

    这回好好用半平面交写一次- 看了cls当年写的代码看了好久大概看懂了-cls太强辣 #include<cstdio> #include<iostream> #include&l ...

  3. BZOJ 1038 ZJOI2008 瞭望塔 半平面交

    题目大意及模拟退火题解:见 http://blog.csdn.net/popoqqq/article/details/39340759 这次用半平面交写了一遍--求出半平面交之后.枚举原图和半平面交的 ...

  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. QT Creator 转VS2017+QT工程

    因为刚学QT 不熟悉其QT Creator 的开发环境,所以打算用VS2017来开发,因为要跨平台所以打算写出来的代码可以放在linux上编译. 这时就需要将VS2017的工程转换成QT Creato ...

  2. 数据库 MySQL part4

    存储引擎 什么是存储引擎? mysql中建的库是文件夹,建的表是文件.文件有不同的类型,数据库中的表也有不同的类型,表的类型不同,会对应mysql不同的存取机制,表类型又称为存储引擎. 存储引擎说白了 ...

  3. VS2013 执行Enable-Migrations,产生错误的解决办法

    我的错误是:提示文件或资源没有找到”Microsoft.VisualStudio.Shell, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b0 ...

  4. 成都Uber优步司机奖励政策(3月30日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  5. 长沙Uber优步司机奖励政策(12月28日到1月3日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  6. 使用apache cgi运行ruby脚本

    在ubuntu下 进入 /usr/lib/cgi-bin目录 新建文件 ruby.cgi 内容如下 #!/usr/bin/ruby print "Content-type: text/htm ...

  7. GitLab 自动触发 Jenkins 构建

    GitLab 是当前应用非常广泛的 Git Hosting 工具,Jenkins 是非常牛逼的持续集成工具.尽管 GitLab 有内建的 GitLab CI,但它远没有 Jenkins 那么强大好用. ...

  8. Qt-QML-C++交互实现文件IO系统-后继-读取XML文件和创建XML文件

    在前面两篇中,大致完成了一个文件IO的读和写操作.前面两篇文章链接 http://blog.csdn.net/z609932088/article/details/71488250 http://bl ...

  9. 【springmvc+mybatis项目实战】杰信商贸-2.数据库配置

    首先我们来了解项目的架构 我们分别使用了MySql和Oracle数据库,即是异构数据库.我们做到一个平台支持多个数据库.数据库建模我们使用Sybase公司的PowerDesigner(以后简称PD), ...

  10. 爬虫2.1-scrapy框架-两种爬虫对比

    目录 scrapy框架-两种爬虫对比和大概流程 1. 传统spider爬虫 2. crawl型爬虫 3. 循环页面请求 4. scrapy框架爬虫的大致流程 scrapy框架-两种爬虫对比和大概流程 ...