BZOJ 1038 瞭望塔

6 篇文章 0 订阅
3 篇文章 0 订阅

 坑点:初始化 inf 至少为 1e10

更新了半平面交的模板。返回值为false 代表 有两条及以下的边界

返回值为true ,代表有两条及以上的边界,但是返回的交点只有当这些边界围成一个闭合的多边形时才有意义。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const double eps = 1e-12;
const double PI = acos(-1.0);
const int maxn = 2010;
const double inf = 1e10;
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    else return 1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double _x,double _y)
    { x = _x; y = _y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x - b.x, y - b.y);
    }
    double operator ^(const Point &b)const
    {
        return x*b.y - y*b.x; }
    double operator *(const Point &b)const{
        return x*b.x + y*b.y;
    }
    double operator <( const Point& b )const{
        if( x == b.x ) return y < b.y;
        return x< b.x;
    }
};
struct Line
{
    Point s,e;
    double k;
    Line(){}
    Line(Point _s,Point _e)
    { s = _s; e = _e;
        k = atan2(e.y - s.y,e.x - s.x);
    }
    Point operator &(const Line &b)const
    {
        Point res = s;
        double t = ((s - b.s)^(b.s - b.e))/((s - e)^(b.s - b.e));
        res.x += (e.x - s.x)*t;
        res.y += (e.y - s.y)*t;
        return res;
    }
};
bool onright( const Line& a,const Line& b,const Line& c ){
    Point o = b&c;
    if( ( (a.e-a.s)^( o-a.s ) ) < 0 ) return true;
    return false;
}
//半平面交,直线的左边代表有效区域
bool HPIcmp(Line a,Line b)
{
    if(fabs(a.k - b.k) > eps)return a.k < b.k;
    return ((a.s - b.s)^(b.e - b.s)) < 0;
}
Line Q[maxn];
bool HPI(Line L[], int n, Point res[], int &resn)
{
    sort( L,L+n,HPIcmp );
    int head = 0,tail = 0,cnt = 1;
    for(int i = 1;i < n;i++)
        if(sgn(L[i].k - L[i-1].k))
            L[cnt++] = L[i];
    for( int i = 0;i < cnt;i++ ){
        while( tail-head > 1 && onright( L[i],Q[tail-1],Q[tail-2] ) ) tail--;
        while( tail-head > 1 && onright( L[i],Q[head],Q[head+1] ) ) head++;
        Q[tail++] =L[i];
    }
    while( tail-head >1 && onright(Q[head],Q[tail-1],Q[tail-2]) ) tail--;
    while(tail-head >1 && onright(Q[tail-1],Q[head],Q[head+1]) ) head++;
    resn = 0;
    for( int i = head;i < tail-1;i++ ) res[resn++] = Q[i]&Q[i+1];
    if( tail -head >= 3 ) res[resn++] = Q[head]&Q[tail-1];
    if(tail-head < 3) return false;
    return true;
}
double CalcArea(Point p[],int n)
{
    double res = 0;
    for(int i = 0;i < n;i++)
        res += (p[i]^p[(i+1)%n]);
    return fabs(res/2);
}
Line lis[maxn];
Point res[maxn];
double xx[maxn],yy[maxn];
vector<Point> ve1,ve2;
double cal( int p,double x ){
    return ve2[p-1].y + (ve2[p].y-ve2[p-1].y)*(x-ve2[p-1].x)/(ve2[p].x-ve2[p-1].x);
}
double cal2( int p,double x ){
    return ve1[p-1].y + (ve1[p].y-ve1[p-1].y)*(x-ve1[p-1].x)/(ve1[p].x-ve1[p-1].x);
}
int main(){
    int n;
    double mmx = -300,mnx = inf;
    scanf("%d",&n);
    for( int i = 1;i <= n;i++ ) {
        scanf("%lf",&xx[i]); mmx = max( mmx,xx[i] );
        mnx = min( mnx,xx[i] );
    }
    for( int i = 1;i <= n;i++ ) scanf("%lf",&yy[i]);
    if( n == 1 ){
        printf("0.000\n");
        return 0;
    }
    for( int i = 1;i < n;i++ ){
        //ve1.push_back( Point( xx[i],yy[i] ) );
        lis[i-1] = Line( Point(xx[i],yy[i]),Point(xx[i+1],yy[i+1]) );
    }
    lis[n-1] = Line( Point( 1,inf ),Point( 0,inf ) );
    lis[n] = Line( Point( mnx,inf ),Point( mnx,-200 ) );
    lis[n+1] = Line( Point( mmx,-200 ),Point( mmx,inf ) );
    int resn;
    HPI( lis,n+2,res,resn );

    double ans = inf;
    for( int i = 1;i <= n;i++ ){
        ve2.push_back( Point( xx[i],yy[i] ) );
    }
    for( int i = 0;i < resn;i++ ){
        ve1.push_back( Point( res[i] ) );
    }
    sort(ve1.begin(),ve1.end());sort(ve2.begin(),ve2.end() );
    for( int i = 0;i < ve1.size();i++ ){
        int p = upper_bound( ve2.begin(),ve2.end(),ve1[i] )-ve2.begin();
        if( !p ) continue;
        if( p == ve2.size() ){
            if( !(sgn(ve1[i].x-ve2[p-1].x)) ){
                ans = min( ans,ve1[i].y-ve2[p-1].y );
            }else continue;
        }else{
            double cury  = cal( p,ve1[i].x );
            ans = min( ans,ve1[i].y-cury );
        }
    }

    for( int i = 0;i < ve2.size();i++ ){
        int p = upper_bound( ve1.begin(),ve1.end(),ve2[i] )-ve1.begin();
        if(!p ) continue;
        if( p == ve1.size() ){
            if(!sgn( ve2[i].x - ve1[p-1].x ) ){
                ans = min( ans,ve1[p-1].y-ve2[i].y );
            }else continue;
        }else{
            double cury = cal2( p,ve2[i].x );
            ans = min( ans,cury-ve2[i].y );
        }
    }
    if( !sgn( ans ) ) ans = 0;
    printf("%.3lf",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值