[BZOJ1038][洛谷P2600]-[ZJOI2008]瞭望塔-半平面交

来源:互联网 发布:船越文夫 知乎 编辑:程序博客网 时间:2024/05/21 21:08

这恶心的题,细节实在是有点多啊= =….

题目

BZOJ1038传送门
听说洛谷上的数据好像要苛刻一些,所以也放一个门
洛谷P2600传送门

题目大意

H村村长dadzhi决定在村中建立一个瞭望塔,以此加强村中的治安。将H村抽象为平面轮廓折线,用(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。在不同的位置建造瞭望塔,所需要建造的高度是不同的。请你写一个程序,帮助dadzhi村长计算塔的最小高度。这里写图片描述

输入输出格式

输入格式:
第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1 ~ yn。

输出格式:
包含一个实数,为塔的最小高度,精确到小数点后三位。


解法

多画几个图大概就能看出来做法
正解是半平面交。把相邻村庄之间的连线,只有在连线的一侧可以同时看见两个村庄,很明显是个半平面交。关于半平面交部分,可以参考题目:BZOJ1007水平可见直线 (题目传送门)

很明显瞭望塔要么在转折点处,要么在某个村庄的正上方,建在中间一定不如建在某个端点优。
因此,处理出合法的区域后,枚举每个转折点和村庄,计算建立瞭望塔的高度更新答案。

实现细节比较多
比如答案为-0.000时注意要输出0
还有边界问题,要么在边界加框,要么就要手动算边界点,坐标尽量开得大一点。实现时me写的是后者。
不要eps也可以过,不用太在意eps的问题


下面是自带大常数的代码

#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;const double eps = 1e-9 ;int N ;struct Vector{    double x , y ;    double len(){ return sqrt( x * x + y * y ) ; }    Vector(){} ;    Vector( double x_ , double y_ ) :        x(x_) , y(y_){} ;};typedef Vector Point ;typedef Vector Vv ;int dcmp( const double &x ){    //if( x > -eps && x < eps ) return 0 ;    //return ( x > eps ? 1 : -1 ) ;    if( x == 0 ) return 0 ;    return x > 0 ? 1 : -1 ;}Vv operator + ( const Vv &A , const Vv &B ){ return Vv( A.x + B.x , A.y + B.y ) ; }Vv operator - ( const Vv &A , const Vv &B ){ return Vv( A.x - B.x , A.y - B.y ) ; }Vv operator * ( const Vv &A , const double &p ){ return Vv( A.x * p , A.y * p ) ; }Vv operator / ( const Vv &A , const double &p ){ return Vv( A.x / p , A.y / p ) ; }bool operator ==( const Vv &A , const Vv &B ){ return A.x == B.x && A.y == B.y ; }bool operator < ( const Vv &A , const Vv &B ){ return A.x < B.x || ( A.x == B.x && A.y < B.y ) ; }double Dot  ( const Vv &A , const Vv &B ){ return A.x * B.x + A.y * B.y ; }double Cross( const Vv &A , const Vv &B ){ return A.x * B.y - A.y * B.x ; }struct Line{    Point pp ;    Vector vv ;    double ang ;    Line(){} ;    Line( Point pp_ , Vector vv_ ):        pp(pp_) , vv(vv_){ang = atan2( vv.y , vv.x ) ;} ;    bool operator < ( const Line &A ) const {        return ang < A.ang ;    }};int fr , ba ;Point a[305] , vtx[305] ;Line La[305] , pne[305] ;Point glt( Point P , Vector u , Point Q , Vector v ){    double t1 = Cross( Q - P , v ) / Cross( u , v ) ;    return P + u * t1 ;}void halfPlaneIntersect( Line *La , int siz , Point *p , Line *pne , int &fr , int &ba ){    sort( La + 1 , La + siz + 1 ) ;    fr = 1 , ba = 0 ;    pne[++ba] = La[1] ;    for( int i = 2 ; i <= siz ; i ++ ){        while( ba > fr && dcmp( Cross( p[ba-1] - La[i].pp , La[i].vv ) ) >= 0 ) ba -- ;        while( ba > fr && dcmp( Cross( p[fr] - La[i].pp , La[i].vv ) ) >= 0 ) fr ++ ;        ++ ba ;        pne[ba] = La[i] ;        if( dcmp( pne[ba].ang - pne[ba-1].ang ) == 0 ){            ba -- ;            if( dcmp( Cross( pne[ba].pp - La[i].pp , La[i].vv ) ) >= 0 ) pne[ba] = La[i] ;        }        if( ba > fr )             p[ba-1] = glt( pne[ba].pp , pne[ba].vv , pne[ba-1].pp , pne[ba-1].vv ) ;        }}void solve(){    for( int i = 1 ; i < N ; i ++ )        La[i] = Line( a[i] , a[i+1] - a[i] ) ;    halfPlaneIntersect( La , N - 1 , vtx , pne , fr , ba ) ;    double ans = 1e12 ;    sort( vtx + fr , vtx + ba + 1 - 1 ) ;    a[0] = Point( -1e15 , 0 ) ;    a[N+1] = Point( 1e15 , 0 ) ;    for( int i = 0 , now = fr ; i <= N && now <= ba - 1 ; i ++ ){        while( now <= ba - 1 && a[i].x <= vtx[now].x && a[i+1].x >= vtx[now].x ){            double len = ( vtx[now].x - a[i].x ) / ( a[i+1].x - a[i].x ) ;            ans = min( ans , vtx[now].y - ( a[i].y + ( ( a[i+1] - a[i] ) * len ).y ) ) ;            now ++ ;        }    }    vtx[fr-1] = Point( -1e10 , pne[fr].pp.y + ( pne[fr].vv.y / pne[fr].vv.x ) * (-1e10 - pne[fr].pp.x ) ) ;    vtx[ba] = Point( 1e10  , pne[ba-1].pp.y + ( pne[ba].vv.y / pne[ba].vv.x ) * ( 1e10 - pne[ba].pp.x ) ) ;    for( int i = fr - 1 , now = 1 ; i <= ba - 1 && now <= N ; i ++ ){        while( now <= N && vtx[i].x <= a[now].x && vtx[i+1].x >= a[now].x ){            double len = ( a[now].x - vtx[i].x ) / ( vtx[i+1].x - vtx[i].x ) ;            ans = min( ans , ( vtx[i].y + ( ( vtx[i+1] - vtx[i] ) * len ).y ) - a[now].y ) ;            now ++ ;        }    }    if( dcmp( ans ) <= 0 ) ans = 0 ;    printf( "%.3f" , ans ) ;}int main(){    scanf( "%d" , &N ) ;    for( int i = 1 ; i <= N ; i ++ )        scanf( "%lf" , &a[i].x ) ;    for( int i = 1 ; i <= N ; i ++ )        scanf( "%lf" , &a[i].y ) ;    solve() ;}
原创粉丝点击