bzoj1038 [ZJOI2008]瞭望塔

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

我们先求一个半平面交
答案只可能出现在半平面的折点和地面上的城市折点上
这里写图片描述

tip

在求直线的时候,一定要按顺序
在用线切割的时候,只用给出的n个点组成的线切割
只要涉及到double类型的比较,都要用dcmp
eps=1e-10

这里写代码片
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;

const int N=100001;
const double eps=1e-10;
const double INF=1e10;
struct node{
    double x,y;
    node (double xx=0,double yy=0)
    {
        x=xx;y=yy;
    }
};
node po[N],p[N],q[N],g[N];
int n,m,nn;
double a,b,c;

int dcmp(double x)
{
    if (fabs(x)<eps) return 0;
    else if (x>0) return 1;
    else return -1;
}

node operator +(const node &x,const node &y){return node(x.x+y.x,x.y+y.y);}
node operator -(const node &x,const node &y){return node(x.x-y.x,x.y-y.y);}
node operator *(const node &x,const double &y){return node(x.x*y,x.y*y);}
node operator /(const node &x,const double &y){return node(x.x/y,x.y/y);}

double Cross(const node x,const node y){return x.x*y.y-x.y*y.x;}
double Dot(const node x,const node y){return x.x*y.x+x.y*y.y;}

void getline(node x,node y)
{
    a=y.y-x.y;
    b=x.x-y.x;
    c=x.y*y.x-x.x*y.y;
}

node insert(node x,node y)
{
    double u=fabs(a*x.x+b*x.y+c);
    double v=fabs(a*y.x+b*y.y+c);
    node ans;
    ans.x=(u*y.x+v*x.x)/(u+v);
    ans.y=(u*y.y+v*x.y)/(u+v);
    return ans;
}

void cut()
{
    int cnt=0;
    for (int i=1;i<=m;i++)
    {
        if (dcmp(a*p[i].x+b*p[i].y+c)<=0) q[++cnt]=p[i];  //直线左侧
        else
        {
            if (dcmp(a*p[i-1].x+b*p[i-1].y+c)<0) q[++cnt]=insert(p[i-1],p[i]);
            if (dcmp(a*p[i+1].x+b*p[i+1].y+c)<0) q[++cnt]=insert(p[i+1],p[i]);
        } 
    }
    for (int i=1;i<=cnt;i++) p[i]=q[i];
    p[0]=p[cnt];  p[cnt+1]=p[1];
    m=cnt;
}

void solve()
{
    int i;
    for (i=1;i<=n;i++) p[i]=po[i];
    m=n;
    p[0]=p[n]; p[n+1]=p[1]; po[0]=po[n]; po[n+1]=po[1];
    for (int i=2;i<=nn;i++)   //<=nn
    {
        getline(po[i-1],po[i]);
        cut();
    }
}

void doit()
{
    int i,j,k;
    double ans=1e60;
    g[nn+1]=g[1]; g[0]=g[nn];
    for (i=1;i<=nn;i++)
        for (j=1;j<=m;j++)
            if (dcmp(p[j].x-g[i].x)<=0&&dcmp(p[j+1].x-g[i].x)>=0)
            {
                getline(p[j],p[j+1]);
                double yy=(a*g[i].x+c)/(-b);
                yy=abs(yy-g[i].y);
                if (dcmp(ans-yy)>0) ans=yy;
            }
    for (i=1;i<=m;i++)
        for (j=1;j<=nn;j++)
            if (dcmp(g[j].x-p[i].x)<=0&&dcmp(g[j+1].x-p[i].x)>=0)
            {
                getline(g[j],g[j+1]);
                double yy=(a*p[i].x+c)/(-b);
                yy=abs(yy-p[i].y);
                if (dcmp(ans-yy)>0) ans=yy;
            }
    printf("%0.3lf",ans);
}

int main()
{
    scanf("%d",&n); nn=n;
    if (n==1){printf("0.000");return 0;}
    for (int i=1;i<=n;i++) scanf("%lf",&po[i].x),g[i].x=po[i].x;
    for (int i=1;i<=n;i++) scanf("%lf",&po[i].y),g[i].y=po[i].y;
    po[++n].x=INF; po[n].y=-INF;   //逆时针
    po[++n].x=INF; po[n].y=INF;
    po[++n].x=-INF; po[n].y=INF;
    po[++n].x=-INF; po[n].y=-INF;
    solve();
    doit();
    return 0;
}
posted @ 2017-09-06 20:03  wtt3117  阅读(112)  评论(0编辑  收藏  举报