bzoj 1038 [ZJOI2008]瞭望塔

来源:互联网 发布:linux怎么打开防火墙 编辑:程序博客网 时间:2024/05/17 08:33

1038: [ZJOI2008]瞭望塔

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



【分析】

根据轮廓线造出来一个下凸壳,然后大力观察得出答案一定是由顶点贡献得到的。(都是一次函数嘛)




【代码】

//bzoj 1038 [ZJOI2008]瞭望塔
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define eps 1e-8
#define inf 1e10
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=305;
int n,cnt,top;
double ans=inf;
struct point {double x,y;} p[mxn],t[mxn];
struct line {double k,b;int id;} l[mxn],s[mxn];
inline bool comp1(line l1,line l2)
{
    if(fabs(l1.k-l2.k)<=eps) return l1.b<l2.b;
    return l1.k<l2.k;
}
inline bool comp2(line l1,line l2) {return l1.id<l2.id;}
inline void addline(int id,double x1,double y1,double x2,double y2)
{
    l[++cnt].id=id;
    l[cnt].k=(y2-y1)/(x2-x1);
    l[cnt].b=y1-x1*(y2-y1)/(x2-x1);
}
inline point get(line l1,line l2)
{
    return (point){(l2.b-l1.b)/(l1.k-l2.k),l1.k*(l2.b-l1.b)/(l1.k-l2.k)+l1.b};
}
int main()
{
    int i,j;
    scanf("%d",&n);
    fo(i,1,n) scanf("%lf",&p[i].x);
    fo(i,1,n) scanf("%lf",&p[i].y);
    fo(i,1,n-1) addline(i,p[i].x,p[i].y,p[i+1].x,p[i+1].y);
    sort(l+1,l+n,comp1);cnt=0;
    fo(i,1,n-1)
    {
        while(top && fabs(l[i].k-s[top].k)<=eps) top--;
        while(top>1 && get(l[i],s[top]).x<=get(s[top],s[top-1]).x) top--;
        s[++top]=l[i];
    }
    sort(l+1,l+n,comp2);
    fo(i,1,top-1)
    {
        point P=get(s[i],s[i+1]);
        fo(j,1,n-1)
          if(P.x>=p[j].x && P.x<=p[j+1].x)
          {
             ans=min(ans,P.y-(l[j].k*P.x+l[j].b));
             break;
    }
    }
    fo(i,1,n)
    {
        point P=p[i];
        fo(j,1,top)
        {
            point p1=get(s[j-1],s[j]),p2=get(s[j],s[j+1]);
            if(j==1) p1.x=-inf;
            if(j==top) p2.x=inf;
            if(P.x>=p1.x && P.x<=p2.x)
            {
             ans=min(ans,s[j].k*P.x+s[j].b-P.y);
             break;
   }
        }
    }
    printf("%.3lf\n",ans);
    return 0;
}
/*
Best day of my life.
*/