1038: [ZJOI2008]瞭望塔

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2999  Solved: 1227
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

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

HINT

N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。

Source

[Submit][Status][Discuss]

这题做的真是。。心力交瘁。。其实就是一个半平面交,然而我发现自己实际上完全不会这个东西。

据说模拟退火和三分都可以做,但是考虑将每条边的上半部分求交,最后这个凸包上的点和原折线的这点才可能是答案。

证明应该是分段一次函数的极致只可能出现在端点上。

剩下的就是一系列半平面交模板的问题了,写了一个先将两点式转成点斜式直线方程再求交的函数,WA,发现点斜式根本不能处理与y轴平行的直线。

然后又看了以前模板中的定比分点叉积求交的函数,WA,发现这个只能求线段交点。

https://blog.csdn.net/u013050857/article/details/40923789

最后极不情愿地写了将式子化到底的做法,感觉这个函数根本背不下来。

不过幸好发现了这个问题,否则考场上要是写了就会很惨。

 #include<cmath>
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef double db;
using namespace std; const int N=;
const double eps=1e-;
int n,tot,cnt;
db ans=1e60;
struct P{ db x,y; }p[N],a[N];
struct L{ P a,b; db sl; }l[N],q[N],tmp[N]; double dmult(P a,P b,P c){ return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); }
bool operator <(const L &a,const L &b){ return (a.sl!=b.sl) ? a.sl<b.sl : dmult(a.a,a.b,b.b)<-eps; } P inter(L a,L b){
double A1=a.b.y-a.a.y,B1=a.a.x-a.b.x,C1=-B1*a.a.y-A1*a.a.x;
double A2=b.b.y-b.a.y,B2=b.a.x-b.b.x,C2=-B2*b.a.y-A2*b.a.x;
return (P){(C1*B2-C2*B1)/(B1*A2-B2*A1),(C1*A2-C2*A1)/(A1*B2-A2*B1)};
}
bool jud(L a,L b,L c){ P t=inter(a,b); return dmult(c.a,c.b,t)<-eps; } void work(){
tmp[++tot]=l[];
rep(i,,cnt) if (fabs(l[i].sl-l[i-].sl)>eps) tmp[++tot]=l[i];
rep(i,,tot) l[i]=tmp[i];
int L=,R=; q[++R]=l[]; q[++R]=l[];
rep(i,,tot){
while (L<R && jud(q[R-],q[R],l[i])) R--;
while (L<R && jud(q[L+],q[L],l[i])) L++;
q[++R]=l[i];
}
while (L<R && jud(q[R-],q[R],q[L])) R--;
while (L<R && jud(q[L+],q[L],q[R])) L++;
tot=; rep(i,L,R-) p[++tot]=inter(q[i],q[i+]);
} void getans(){
rep(k,,tot)
rep(i,,n-){
P t=(P){p[k].x,-};
if (p[k].x>=a[i].x && p[k].x<=a[i+].x)
ans=min(ans,p[k].y-inter((L){a[i],a[i+]},(L){t,p[k]}).y);
}
rep(k,,n)
rep(i,,tot-){
P t=(P){a[k].x,-};
if (a[k].x>=p[i].x && a[k].x<=p[i+].x)
ans=min(ans,inter((L){p[i],p[i+]},(L){t,a[k]}).y-a[k].y);
}
} int main(){
scanf("%d",&n);
rep(i,,n) scanf("%lf",&a[i].x);
rep(i,,n) scanf("%lf",&a[i].y);
a[]=(P){a[].x,}; a[n+]=(P){a[n].x,};
rep(i,,n) l[++cnt]=(L){a[i],a[i+],atan2(a[i+].y-a[i].y,a[i+].x-a[i].x)};
sort(l+,l+cnt+); work(); getans(); printf("%.3lf\n",ans);
return ;
}

UPD:感觉自己十分愚蠢,与y轴平行的直线判一下不就好了。

 #include<cmath>
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
#define A double k2=(b.b.y-b.a.y)/(b.b.x-b.a.x),b2=b.a.y-k2*b.a.x
#define B double k1=(a.b.y-a.a.y)/(a.b.x-a.a.x),b1=a.a.y-k1*a.a.x
typedef double db;
using namespace std; const int N=;
const double eps=1e-;
int n,tot,cnt;
db ans=1e60;
struct P{ db x,y; }p[N],a[N];
struct L{ P a,b; db sl; }l[N],q[N],tmp[N]; double dmult(P a,P b,P c){ return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); }
bool operator <(const L &a,const L &b){ return (a.sl!=b.sl) ? a.sl<b.sl : dmult(a.a,a.b,b.b)<-eps; } P inter(L a,L b){
if (a.a.x==a.b.x){ A; return (P){a.a.x,k2*a.a.x+b2}; }
if (b.a.x==b.b.x){ B; return (P){b.a.x,k1*b.a.x+b1}; }
A; B; double x=(b2-b1)/(k1-k2),y=k1*x+b1;
return (P){x,y};
} bool jud(L a,L b,L c){ P t=inter(a,b); return dmult(c.a,c.b,t)<-eps; } void work(){
tmp[++tot]=l[];
rep(i,,cnt) if (fabs(l[i].sl-l[i-].sl)>eps) tmp[++tot]=l[i];
rep(i,,tot) l[i]=tmp[i];
int L=,R=; q[++R]=l[]; q[++R]=l[];
rep(i,,tot){
while (L<R && jud(q[R-],q[R],l[i])) R--;
while (L<R && jud(q[L+],q[L],l[i])) L++;
q[++R]=l[i];
}
while (L<R && jud(q[R-],q[R],q[L])) R--;
while (L<R && jud(q[L+],q[L],q[R])) L++;
tot=; rep(i,L,R-) p[++tot]=inter(q[i],q[i+]);
} void getans(){
rep(k,,tot)
rep(i,,n-){
P t=(P){p[k].x,-};
if (p[k].x>=a[i].x && p[k].x<=a[i+].x)
ans=min(ans,p[k].y-inter((L){a[i],a[i+]},(L){t,p[k]}).y);
}
rep(k,,n)
rep(i,,tot-){
P t=(P){a[k].x,-};
if (a[k].x>=p[i].x && a[k].x<=p[i+].x)
ans=min(ans,inter((L){p[i],p[i+]},(L){t,a[k]}).y-a[k].y);
}
} int main(){
freopen("tower.in","r",stdin);
freopen("tower.out","w",stdout);
scanf("%d",&n);
rep(i,,n) scanf("%lf",&a[i].x);
rep(i,,n) scanf("%lf",&a[i].y);
a[]=(P){a[].x,}; a[n+]=(P){a[n].x,};
rep(i,,n) l[++cnt]=(L){a[i],a[i+],atan2(a[i+].y-a[i].y,a[i+].x-a[i].x)};
sort(l+,l+cnt+); work(); getans(); printf("%.3lf\n",ans);
return ;
}

[BZOJ1038][ZJOI2008]瞭望塔(半平面交)的更多相关文章

  1. bzoj千题计划126:bzoj1038: [ZJOI2008]瞭望塔

    http://www.lydsy.com/JudgeOnline/problem.php?id=1038 本题可以使用三分法 将点按横坐标排好序后 对于任意相邻两个点连成的线段,瞭望塔的高度 是单峰函 ...

  2. 「BZOJ1038」「洛谷P2600」「ZJOI2008」瞭望塔 半平面交+贪心

    题目链接 BZOJ/洛谷 题目描述 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安. 我们将H村抽象为一维的轮廓.如下图所示: 我们可以用一条山的上方 ...

  3. bzoj 1038 瞭望塔 半平面交+分段函数

    题目大意 给你一座山,山的形状在二维平面上为折线 给出\((x_1,y_1),(x_2,y_2)...(x_n,y_n)\)表示山的边界点或转折点 现在要在\([x_1,x_n]\)(闭区间)中选择一 ...

  4. [日常摸鱼]bzoj1038 [ZJOI2008]瞭望塔-模拟退火/几何

    题意:给一条平面内$n$个点的折线,要求在折线上搞一个高度$h$的瞭望塔,能够看见折线上所有的点,求$h$的最小值($n \leq 300$) updata2018.1.21 正解半平面交在另一篇里面 ...

  5. bzoj1038: [ZJOI2008]瞭望塔

    Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, ...

  6. BZOJ-1038 [ZJOI2008]瞭望塔

    先求半平面交,然后建塔的地方肯定是在半平面交的交点上或者是在地面线段的交点上. #include <cstdlib> #include <cstdio> #include &l ...

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

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

  8. 【半平面交】bzoj1038 [ZJOI2008]瞭望塔

    http://m.blog.csdn.net/blog/qpswwww/44105605 #include<cstdio> #include<cmath> #include&l ...

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

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

随机推荐

  1. Python 3基础教程1-环境安装和运行环境

    本系列开始介绍Python3的基础教程,为什么要选中Python 3呢?之前呢,学Python 2,看过笨方法学Python,学了不到一个礼拜,就开始用Python写Selenium脚本.最近看到一些 ...

  2. 孤荷凌寒自学python第七天 列表的复制与序列的基本运算

    孤荷凌寒自学python第七天 列表的复制与序列的基本运算 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) (同步语音:https://www.ximalaya.com/keji/191030 ...

  3. java实现最大堆

    优先队列 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有最高级先出 (first in, ...

  4. CodeForces Round #515 Div.3 A. Vova and Train

    http://codeforces.com/contest/1066/problem/A Vova plans to go to the conference by train. Initially, ...

  5. Mac平台重新设置MySQL的root密码

    Mac OS X - 重置 MySQL Root 密码 您是否忘记了Mac OS 的MySQL的root密码? 通过以下4步就可重新设置新密码: 1.  停止 mysql server.  通常是在 ...

  6. 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

    题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...

  7. 洛谷 P2597 [ZJOI2012]灾难 解题报告

    P2597 [ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发 ...

  8. Hibernate中的延迟加载及fetch

    Hibernate中的延迟加载 1.类级别的查询策略: lazy  :  true(默认值) false(立即加载) 2.多对一关联的查询策略: lazy:  proxy(默认值) no-proxy ...

  9. ListView控件的不为人知的秘密

    使用ListView控件展示数据 1.图像列表控件(ImageList控件) 图像列表控件(ImageList控件)是含有图像对象的集合,可以通过索引或关键字引用该集合的每个对象,ImageList控 ...

  10. 厌倦了ListBox打印消息,使用RichTextBox试试吧

    背景 Winform打印后台线程运行时消息,习惯用ListBox,有时候某行消息过长,设置个Tooltip控件提示全部信息.后来无意中看到同事使用RichTextBox打印消息,然后在不同的消息类别上 ...