[BZOJ1038][ZJOI2008]瞭望塔(半平面交)

=== ===

这里放传送门

=== ===

题解

可以发现对于一个山坡来说,建造的瞭望塔能看到它的条件就是塔顶连接山谷的那条线的斜率绝对值大于山坡斜率的绝对值,如图:
[BZOJ1038][ZJOI2008]瞭望塔(半平面交)_第1张图片
1号和3号山坡是可以被看到的,而2号不可以。
我们可以发现只要把所有的山坡向上做半平面交,瞭望塔的顶点一定要在交集内部。可以发现最小高度的瞭望塔至少有一个顶点在凸多边形或山坡的顶点上,那么为了求出最小的高度,我们可以用 O(n2) 的时间枚举凸多边形和山坡的所有顶点和边来计算高度,也可以用两个指针扫一下。

代码

#include
#include
#include
#include
using namespace std;
const double eps=1e-12;
const double inf=1e10;
int n;
double ans;
struct Vector{
    double x,y;
    Vector(double X=0,double Y=0){x=X;y=Y;}
    Vector operator + (const Vector &a){return Vector(x+a.x,y+a.y);}
    Vector operator - (const Vector &a){return Vector(x-a.x,y-a.y);}
    double operator * (const Vector &a){return x*a.y-y*a.x;}
    Vector mul(double t){return Vector(x*t,y*t);}
}v[310],tmp,w,ip;
int comp(Vector a,Vector b){
    return a.xstruct Polygon{
    Vector p[500];
    int c;
    Polygon(){c=0;memset(p,0,sizeof(p));}
    void clear(){
        p[1]=Vector(-inf,inf);
        p[2]=Vector(-inf,-inf);
        p[3]=Vector(inf,-inf);
        p[4]=Vector(inf,inf);
        p[5]=p[1];c=4;
    }
    void add(Vector v){p[++c]=v;}
    void Sort(){sort(p+1,p+c+1,comp);}
}poly;
bool Ins(Vector A,Vector B,Vector C,Vector D){
    Vector v=B-A,w=D-C,u=D-A;
    if (fabs(w*v)return false;
    w=C-A;
    return ((v*w)*(v*u)<-eps);
}
Vector GLI(Vector P,Vector v,Vector Q,Vector w){
    Vector u=P-Q;
    double t=(w*u)/(v*w);
    return P+v.mul(t);
}
Polygon CutPolygon(Polygon poly,Vector A,Vector B){
    Vector C,D,ip;
    Polygon newp=Polygon();
    for (int i=1;i<=poly.c;i++){
        C=poly.p[i];D=poly.p[i+1];
        if ((B-A)*(C-A)>-eps) newp.add(C);
        if (Ins(A,B,C,D)){
            ip=GLI(A,B-A,C,D-C);
            newp.add(ip);
        }
    }
    newp.p[newp.c+1]=newp.p[1];
    return newp;
}
int main()
{
    scanf("%d",&n);poly.clear();
    for (int i=1;i<=n;i++) scanf("%lf",&v[i].x);
    for (int i=1;i<=n;i++) scanf("%lf",&v[i].y);
    for (int i=1;i1]);
    v[0]=Vector(-inf,-inf);v[n+1]=Vector(inf,-inf);
    poly.Sort();w=Vector(0,1);ans=1e60;
    for (int i=1,ptr=0;i<=poly.c;i++){
        tmp=poly.p[i];
        while (ptr<=n&&v[ptr].xif (ptr>n) break;//注意不能计算斜线段
        ip=GLI(tmp,w,v[ptr-1],v[ptr]-v[ptr-1]);
        if (ip.x-v[1].x>-eps&&v[n].x-ip.x>-eps)
          ans=min(ans,fabs(ip.y-tmp.y));
    }
    poly.p[0]=Vector(-inf,inf);
    poly.p[poly.c+1]=Vector(inf,inf);
    for (int i=1,ptr=0;i<=n;i++){
        tmp=v[i];
        while (ptr<=poly.c&&poly.p[ptr].x//找到顶点正下方的线段
        if (ptr>poly.c) break;
        ip=GLI(tmp,w,poly.p[ptr-1],poly.p[ptr]-poly.p[ptr-1]);
        ans=min(ans,fabs(ip.y-tmp.y));
    }
    printf("%.3lf\n",ans);
    return 0;
}

你可能感兴趣的:(BZOJ,狂掉精度的计算几何)