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. adb启动和关闭

    启动adb服务: cmd("adb start-server"); 关闭adb服务: cmd("adb start-server");

  2. UnitOfWork知多少 【转】

    原文链接:https://www.cnblogs.com/sheng-jie/p/7416302.html 1. 引言 Maintains a list of objects affected by ...

  3. 第一次玩博客 感觉自己特别low

    第一天来  来好激动第一天来  来好激动第一天来  来好激动第一天来  来好激动第一天来  来好激动第一天来  来好激动第一天来  来好激动第一天来  来好激动第一天来  来好激动第一天来  来好激动 ...

  4. Spring 学习笔记(六)—— AOP的简单理解

    系统中的业务可以分为核心关注点和横切关注点. 核心关注点时业务处理的主要流程,而横切关注点是与核心业务无关但更为通用的业务. 各个横切关注点离散地穿插于核心业务之中,导致系统地每一个模块都与这些业务具 ...

  5. java窗口程序初学组件小总结

    容器(可以放组件)JPanel默认的布局管理器是FlowLayout:JPanel panel=new JPanel(); 按钮JButton(可以为汉字 也可以是图片):JButton button ...

  6. json字符串数组判断其中

    嘴挺笨的描述不清,直接看图,console.log(data1)是下图 获取的table中的数据组成的json对象(这里我不明白json对象啊json字符串啊json数组啊.我只会- 需要啥就转换成啥 ...

  7. 冒泡排序 [组合数学+dp]

    题面 思路 一眼看过去以为NOI2018的题出出来了= =贼吓人 首先,对于这个难度,我们有一个比较明显的结论: 一个序列的难度,等于这个东西: $hard=max(\sum_{j=i+1}^n[a_ ...

  8. 威士忌(whiskey)

    威士忌(whiskey) 题目描述 Alan 喝了假威士忌,想问你一个问题: nvliu66 推荐大家读三本书<百年孤独>.<城市发展史>.<美国大城市的生与死>, ...

  9. 262144 (game)

    262144 (game) 题目描述 Bessie likes downloading games to play on her cell phone, even though she does fi ...

  10. JavaScript 代码性能优化总结

    本文转自:http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=400360237&idx=2&sn=eb00241cb3b ...