• 【BZOJ】【1038】【ZJOI2008】瞭望塔


    计算几何/半平面交


      说是半平面交,实际上只是维护了个下凸壳而已……同1007水平可见直线

      对于每条线段,能看到这条线段的点都在这条线段的“上方”,那么对所有n-1条线段求一个可视区域的交,就是求一个半平面交……(好扯)

      一开始我想的是:直接找到这个下凸壳的最低点,它的y值就是答案辣~但是明显不对>_>这题让求的是塔的最低高度……不光要考虑塔顶,还要看塔底的啊!

      那么我们怎么找呢?我们可以发现:随着x的变化,塔高(就是地面到凸壳的竖直距离,y坐标之差)是一个分段函数,分段点就是地面的折点以及凸壳的顶点!而且在每一段里面,塔高的值是一个一次函数!经过大胆猜想,小(bu)心(yong)证明我们发现:分段一次函数的极值在分段点和边界点处取到。

      那么就是对这些点算一下答案就可以了……点数是O(n)的……

     1 /**************************************************************
     2     Problem: 1038
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:0 ms
     7     Memory:1292 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1038
    11 #include<cmath>
    12 #include<vector>
    13 #include<cstdio>
    14 #include<cstring>
    15 #include<cstdlib>
    16 #include<iostream>
    17 #include<algorithm>
    18 #define rep(i,n) for(int i=0;i<n;++i)
    19 #define F(i,j,n) for(int i=j;i<=n;++i)
    20 #define D(i,j,n) for(int i=j;i>=n;--i)
    21 #define pb push_back
    22 using namespace std;
    23 inline int getint(){
    24     int v=0,sign=1; char ch=getchar();
    25     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    26     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    27     return v*sign;
    28 }
    29 const int N=310,INF=~0u>>2;
    30 typedef long long LL;
    31 typedef double lf;
    32 const lf eps=1e-8;
    33 /******************tamplate*********************/
    34 struct Point{
    35     lf x,y;
    36     void read(){scanf("%lf%lf",&x,&y);}
    37 }p[N];
    38 struct Line{double k,b;}l[N],st[N];
    39 Line make_line(Point a,Point b){
    40     Line tmp;
    41     tmp.k=(a.y-b.y)/(a.x-b.x);
    42     tmp.b=a.y-tmp.k*a.x;
    43     return tmp;
    44 }
    45 int n,top;
    46 inline bool cmp(Line a,Line b){
    47     if (fabs(a.k-b.k)<eps) return a.b<b.b;
    48     return a.k<b.k;
    49 }
    50 double crossx(Line x1,Line x2){
    51     return (x2.b-x1.b)/(x1.k-x2.k);
    52 }
    53 void insert(Line a){
    54     while(top){
    55         if (fabs(st[top].k-a.k)<eps) top--;
    56         else if (top>1 && crossx(a,st[top-1])<=
    57                           crossx(st[top],st[top-1])) top--;
    58         else break;
    59     }
    60     st[++top]=a;
    61 }
    62 lf Up(lf x){
    63     lf ans=0.0;
    64     F(i,1,top)
    65         ans=max(ans,st[i].k*x+st[i].b);
    66     return ans;
    67 }
    68 lf Down(lf x){
    69     int pos;
    70     for(pos=1;pos<n && p[pos+1].x<x;pos++);
    71     if (pos==n) return -1e10;
    72     Line tmp=make_line(p[pos],p[pos+1]);
    73     return tmp.k*x+tmp.b;
    74 }
    75  
    76 int main(){
    77 #ifndef ONLINE_JUDGE
    78     freopen("1038.in","r",stdin);
    79     freopen("1038.out","w",stdout);
    80 #endif
    81     n=getint();
    82     F(i,1,n) scanf("%lf",&p[i].x);
    83     F(i,1,n) scanf("%lf",&p[i].y);
    84     F(i,1,n-1) l[i]=make_line(p[i+1],p[i]);
    85     sort(l+1,l+n,cmp);
    86     F(i,1,n-1) insert(l[i]);
    87     lf ans=1e10;
    88     F(i,1,n) ans=min(ans,Up(p[i].x)-p[i].y);
    89     F(i,2,top){
    90         Point p;
    91         p.x=crossx(st[i-1],st[i]);
    92         p.y=st[i].k*p.x+st[i].b;
    93         ans=min(ans,p.y-Down(p.x));
    94     }
    95     printf("%.3lf
    ",ans);
    96     return 0;
    97 }
    View Code

    1038: [ZJOI2008]瞭望塔

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1043  Solved: 470
    [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

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

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    Python将文本生成二维码
    Python 发送邮件
    北京地铁月度消费总金额计算(Python版)
    将w3cplus网站中的文章页面提取并导出为pdf文档
    [开发笔记]-MarkDown语法
    linux多版本php安装+采坑指南
    浏览器跨域暴力解决
    php7使用xhprof测试php性能
    vscode使用xdebug断点调试php代码(无论win还是linux)
    ghostscript之pdf处理
  • 原文地址:https://www.cnblogs.com/Tunix/p/4426259.html
Copyright © 2020-2023  润新知