1038: [ZJOI2008]瞭望塔

半平面交。

半平面指的就是一条直线的左面(也不知道对不对)

半平面交就是指很多半平面的公共部分。

这道题的解一定在各条直线的半平面交中。

而且瞭望塔只可能在各个点或者半平面交折线的拐点处。

求出半平面交,枚举即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define eps 1e-7
using namespace std;
const int maxn = 300 + 10;

struct Point {
    double x,y;    
}p[maxn],t;

struct Line {
    double k,b;
    
    void init(Point p1,Point p2) {
        k=(p1.y-p2.y)/(p1.x-p2.x);
        b=p2.y-k*p2.x;
    }
}l[maxn],s[maxn];

int n,sp;
double res=1e11;

bool cmp(Line x,Line y) {
    if(abs(x.k-y.k)<eps) return x.b<y.b;
    return x.k<y.k;
}

Point inter(Line l1,Line l2) {
    Point res;
    res.x=(l2.b-l1.b)/(l1.k-l2.k);
    res.y=l1.k*res.x+l1.b;
    return res;
}

void push(Line l) {
    while(sp>=2 && inter(s[sp],l).x < inter(s[sp-1],s[sp]).x) sp--;    
    s[++sp]=l;
}

double f(double x) {
    double res=0;
    for(int i=1;i<=sp;i++) res=max(res,s[i].k*x+s[i].b);
    return res;
}

double g(double x) {
    int i;
    for(i=n;i&&x<p[i].x;i--);
    return p[i].y+(x-p[i].x)/(p[i+1].x-p[i].x)*(p[i+1].y-p[i].y);    
}


int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf",&p[i].x);
    for(int i=1;i<=n;i++) scanf("%lf",&p[i].y);
    for(int i=1;i<n;i++) l[i].init(p[i],p[i+1]);
    sort(l+1,l+n,cmp);
    for(int i=1;i<n;i++) if(i==n-1 || abs(l[i].k-l[i+1].k)>eps) push(l[i]);
    
    for(int i=1;i<=n;i++) res=min(res,f(p[i].x)-p[i].y);
    for(int i=1;i<sp;i++) {
        t=inter(s[i],s[i+1]);
        res=min(res,t.y-g(t.x));
    }
    printf("%.3lf\n",res);
    return 0;
}
posted @ 2016-07-09 19:27  invoid  阅读(367)  评论(0编辑  收藏  举报