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

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

题目

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

题目大意

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

输入输出格式

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

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


解法

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

很明显瞭望塔要么在转折点处,要么在某个村庄的正上方,建在中间一定不如建在某个端点优(画几条直线模拟一下就知道了)。
因此,处理出合法的区域后,枚举每个转折点和村庄,计算建立瞭望塔的高度更新答案。

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


下面是自带大常数的代码

#include 
#include 
#include 
#include 
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() ;
}

你可能感兴趣的:([BZOJ1038][洛谷P2600]-[ZJOI2008]瞭望塔-半平面交)