bzoj1038

这是一道非常有意思的题目

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,注意考虑实数误差带来的问题。

题解

经过研究,我们发现能看见一段山坡的是一个半平面

于是半平面交

我们得到了一个上凸壳和一段折线,求这两个玩意水平的最短距离

这个嘛,我们发现一定是在上凸壳或者折线的顶点处最小

然后明显一个点对应的一段线是单调的。

问题解决

虽然这题只有300

但是这个能做300000

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
#define linf 1e15
using namespace std;
const int N=100001;
typedef double db;
int n,m,L,R,p;
db ans=1e60;
struct P{db x,y;} a[N],c[N],t,tt;
struct line{P a,b;db slop;} l[N],q[N];
il P operator-(P a,P b){
    return (P){a.x-b.x,a.y-b.y};
}
il db operator*(P a,P b){
    return a.x*b.y-a.y*b.x;
}
il bool cmp(line a,line b){
    if(a.slop!=b.slop) return a.slop<b.slop;
    return (a.b-a.a)*(b.b-a.a)>0;
}
il P inter(line a,line b){
    double k1,k2,t;
    k1=(b.b-a.a)*(a.b-a.a);
    k2=(a.b-a.a)*(b.a-a.a);
    t=k1/(k1+k2);P ans;
    ans.x=b.b.x+(b.a.x-b.b.x)*t;
    ans.y=b.b.y+(b.a.y-b.b.y)*t;
    return ans;
}
il bool jud(line a,line b,line t){
    P p=inter(a,b);
    return (p-t.a)*(t.b-t.a)>0;
}
il void print(P a){
    printf("(%lf,%lf)\n",a.x,a.y);
}
int main(){
    scanf("%d",&n);m=n-1;
    for(int i=1;i<=n;i++) scanf("%lf",&a[i].x);
    for(int i=1;i<=n;i++) scanf("%lf",&a[i].y);
    for(int i=1;i<n;i++){
        l[i].a=a[i];
        l[i].b=a[i+1];
    }
    l[++m]=(line){(P){a[1].x,1e7},a[1]};
    l[++m]=(line){a[n],(P){a[n].x,1e7}};
    for(int i=1;i<=m;i++)
        l[i].slop=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);
    sort(l+1,l+m+1,cmp);
    L=1;R=2;
    q[1]=l[1];q[2]=l[2];
    for(int i=3;i<=m;i++){
        while(L<R&&jud(q[R-1],q[R],l[i])) R--;
        while(L<R&&jud(q[L],q[L+1],l[i])) L++;
        q[++R]=l[i];
    }
    while(L<R&&jud(q[R-1],q[R],q[L])) R--;
    while(L<R&&jud(q[L],q[L+1],q[R])) L++;
    for(int i=L;i<R;i++)
        c[++p]=inter(q[i],q[i+1]);
    for(int i=1,j=1;i<=n;i++){
        while(j<p&&(!(c[j].x<=a[i].x&&a[i].x<=c[j+1].x))) j++;
        if(j<p){
            tt=(P){a[i].x,-1};
            t=inter((line){tt,a[i]},(line){c[j],c[j+1]});
            ans=min(ans,t.y-a[i].y);
        }
    }
    for(int i=1,j=1;i<=p;i++){
        while(j<n&&(!(a[j].x<=c[i].x&&c[i].x<=a[j+1].x))) j++;
        if(j<n){
            tt=(P){c[i].x,-1};
            t=inter((line){tt,c[i]},(line){a[j],a[j+1]});
            ans=min(ans,c[i].y-t.y);
        }
    }
    printf("%.3lf",ans);
    return 0;
}
时间: 2024-10-06 03:06:29

bzoj1038的相关文章

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

http://m.blog.csdn.net/blog/qpswwww/44105605 #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define EPS 0.0000001 #define N 311 typedef double db; const db PI=acos(-1.0); struct Point{db x,y;}; typedef Point Ve

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

[BZOJ1038][ZJOI2008]瞭望塔 Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn.瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置.可见在不同的位置建造瞭望塔,所需要建造的

bzoj1038题解

[题意分析] 求一个下凸壳与一段折线的距离. [解题思路] 先把直线按斜率排序,求出下凸壳,然后枚举所有的顶点的x坐标求最短y坐标差. [参考代码] 1 #include <algorithm> 2 #include <cstdio> 3 #define REP(i,low,high) for(register int i=(low);i<=(high);++i) 4 #define __function__(type) /*__attribute__((optimize(&

【BZOJ1038】【ZJOI2008】瞭望塔 [模拟退火]

瞭望塔 Time Limit: 10 Sec  Memory Limit: 162 MB[Submit][Status][Discuss] Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安. 我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn. 瞭望塔可以建造在[x1, xn]间的任意

BZOJ-1038 [ZJOI2008]瞭望塔

先求半平面交,然后建塔的地方肯定是在半平面交的交点上或者是在地面线段的交点上. #include <cstdlib> #include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <cctype> #define rep(i, l, r) for(int i=l; i<=r

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

http://www.lydsy.com/JudgeOnline/problem.php?id=1038 本题可以使用三分法 将点按横坐标排好序后 对于任意相邻两个点连成的线段,瞭望塔的高度 是单峰函数,而且是下凸函数 感性理解单峰就是 瞭望塔建的靠左,为了能看到右边的,要高一点 瞭望塔建的靠右,为了能看到左边的,要高一点 所以 枚举所有线段,三分线段上建造瞭望塔的位置,所有线段上的瞭望塔高度取最小 #include<cmath> #include<cstdio> #include

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

这回好好用半平面交写一次- 看了cls当年写的代码看了好久大概看懂了-cls太强辣 #include<cstdio> #include<iostream> #include<algorithm> #define rep(i,n) for(register int i=1;i<=n;i++) #define REP(i,a,b) for(register int i=a;i<=b;i++) #define debug(x) cout<<#x<

2016.08.06计算几何总结测试day1

T1 bzoj1132[POI2008]TRO 还是太弱了....测试时看到这题直接懵逼,极角排序什么的根本想不起来,只会n^3暴力怎么破......不过竟然有84.....QAQ 正解是n^2logn的,首先为了避免算重,以点的x坐标为第一关键字和y坐标为第二关键字排好序,然后O(n)枚举当前点计算以当前点为三角形的一个顶点的三角形面积之和. 显然不能n^2枚举,于是想到nlogn极角排序,以当前点为原点建一个平面直角坐标系,加一个前缀和将计算优化到O(n),于是就是n^2logn的了 至于怎

[转载]hzwer的bzoj题单

counter: 664BZOJ1601 BZOJ1003 BZOJ1002 BZOJ1192 BZOJ1303 BZOJ1270 BZOJ3039 BZOJ1191 BZOJ1059 BZOJ1202 BZOJ1051 BZOJ1001 BZOJ1588 BZOJ1208 BZOJ1491 BZOJ1084 BZOJ1295 BZOJ3109 BZOJ1085 BZOJ1041 BZOJ1087 BZOJ3038 BZOJ1821 BZOJ1076 BZOJ2321 BZOJ1934 BZOJ