• HDU 4643 GSM 算术几何


    当火车处在换基站的临界点时,它到某两基站的距离相等。因此换基站的位置一定在某两个基站的中垂线上,

    我们预处理出任意两基站之间的中垂线,对于每次询问,求询问线段与所有中垂线的交点。

    检验这些交点是否满足条件(详见代码),如果满足,那么它是一个交换点。

    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    const int MAXN = 60;
    
    const double eps = 1e-7;
    
    struct Point
    {
        double x, y;
        Point( double x = 0, double y = 0 ):x(x), y(y) { }
    };
    
    typedef Point Vector;
    
    struct Line
    {
        Point s;
        Vector v;
        Line( Point s = Point(), Point v = Point() ):
            s(s), v(v) { }
    };
    
    int dcmp( double x )    //控制精度
    {
        if ( fabs(x) < eps ) return 0;
        else return x < 0 ? -1 : 1;
    }
    
    Vector operator+( Vector A, Vector B )       //向量加
    {
        return Vector( A.x + B.x, A.y + B.y );
    }
    
    Vector operator-( Vector A, Vector B )       //向量减
    {
        return Vector( A.x - B.x, A.y - B.y );
    }
    
    Vector operator*( Vector A, double p )      //向量数乘
    {
        return Vector( A.x * p, A.y * p );
    }
    
    Vector operator/( Vector A, double p )      //向量数除
    {
        return Vector( A.x / p, A.y / p );
    }
    
    bool operator<( const Point& A, const Point& B )   //两点比较
    {
        return dcmp( A.x - B.x ) < 0 || ( dcmp( A.x - B.x ) == 0 && dcmp( A.y - B.y ) < 0 );
    }
    
    bool operator==( const Point& a, const Point& b )   //两点相等
    {
        return dcmp( a.x - b.x ) == 0 && dcmp( a.y - b.y ) == 0;
    }
    
    double Dot( Vector A, Vector B )    //向量点乘
    {
        return A.x * B.x + A.y * B.y;
    }
    
    double Length( Vector A )           //向量模
    {
        return sqrt( Dot( A, A ) );
    }
    
    double Angle( Vector A, Vector B )    //向量夹角
    {
        return acos( Dot(A, B) / Length(A) / Length(B) );
    }
    
    double Cross( Vector A, Vector B )   //向量叉积
    {
        return A.x * B.y - A.y * B.x;
    }
    
    double Area2( Point A, Point B, Point C )    //向量有向面积
    {
        return Cross( B - A, C - A );
    }
    
    Vector Rotate( Vector A, double rad )    //向量旋转
    {
        return Vector( A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad) );
    }
    
    Vector Normal( Vector A )    //向量单位法向量
    {
        double L = Length(A);
        return Vector( -A.y / L, A.x / L );
    }
    
    Point GetLineIntersection( Point P, Vector v, Point Q, Vector w )   //两直线交点
    {
        Vector u = P - Q;
        double t = Cross( w, u ) / Cross( v, w );
        return P + v * t;
    }
    
    double DistanceToLine( Point P, Point A, Point B )    //点到直线的距离
    {
        Vector v1 = B - A, v2 = P - A;
        return fabs( Cross( v1, v2 ) ) / Length(v1);
    }
    
    double DistanceToSegment( Point P, Point A, Point B )   //点到线段的距离
    {
        if ( A == B ) return Length( P - A );
        Vector v1 = B - A, v2 = P - A, v3 = P - B;
        if ( dcmp( Dot(v1, v2) ) < 0 ) return Length(v2);
        else if ( dcmp( Dot(v1, v3) ) > 0 ) return Length(v3);
        else return fabs( Cross( v1, v2 ) ) / Length(v1);
    }
    
    Point GetLineProjection( Point P, Point A, Point B )    // 点在直线上的投影
    {
        Vector v = B - A;
        return A + v*( Dot(v, P - A) / Dot( v, v ) );
    }
    
    bool SegmentProperIntersection( Point a1, Point a2, Point b1, Point b2 )  //线段相交,交点不在端点
    {
        double c1 = Cross( a2 - a1, b1 - a1 ), c2 = Cross( a2 - a1, b2 - a1 ),
                    c3 = Cross( b2 - b1, a1 - b1 ), c4 = Cross( b2 - b1, a2 - b1 );
        return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
    }
    
    bool OnSegment( Point p, Point a1, Point a2 )   //点在线段上,不包含端点
    {
        return dcmp( Cross(a1 - p, a2 - p) ) == 0 && dcmp( Dot( a1 - p, a2 - p ) ) < 0;
    }
    
    /****************以上模板******************/
    
    int N, M;
    Point city[MAXN];      //城市
    Point GSM[MAXN];       //基站
    Line L[MAXN][MAXN];    //点[i][j]之间的中垂线
    
    void init()
    {
        for ( int i = 1; i <= M; ++i )
            for ( int j = i + 1; j <= M; ++j )
            {
                Point mid = Point( (GSM[i].x+GSM[j].x)/2.0, (GSM[i].y+GSM[j].y)/2.0 );
                L[i][j] = Line( mid, Normal( GSM[j] - GSM[i] ) );
                L[j][i] = L[i][j];
            }
        return;
    }
    
    //判断交点是否在线段上
    bool check( Point st, Point ed, Point cp )
    {
        return ( st < cp || st == cp ) && ( cp < ed || cp == ed );
    }
    
    //假设我在此交点交换基站
    //那么交点到形成 该中垂线的线段的其中一端点 的距离 L 应该是最小的
    //判断是否有点到交点的距离小于L,如果有,则不是在这一点交换的基站
    bool check2( double limit, Point jiao )
    {
        for ( int i = 1; i <= M; ++i )
        {
            double dis = Length( GSM[i] - jiao );
            if ( dcmp( dis - limit ) < 0 ) return false;
        }
        return true;
    }
    
    int main()
    {
        //freopen( "in.txt", "r", stdin );
        //freopen( "s.txt", "w", stdout );
        while ( ~scanf( "%d%d", &N, &M ) )
        {
            for ( int i = 1; i <= N; ++i )
                scanf( "%lf%lf", &city[i].x, &city[i].y );
    
            for ( int i = 1; i <= M; ++i )
                scanf( "%lf%lf", &GSM[i].x, &GSM[i].y );
    
            init();   //初始化所有中垂线
            int Q;
            scanf( "%d", &Q );
            while ( Q-- )
            {
                int a, b;
                scanf( "%d%d", &a, &b );
                if ( a > b ) swap( a, b );
                Line train = Line( city[a], city[b] - city[a] );  //火车行进路线
                int huan = 0;         //换基站次数
                for ( int i = 1; i <= M; ++i )
                    for ( int j = i + 1; j <= M; ++j )
                    {
                        if ( dcmp( Cross( train.v, L[i][j].v ) ) == 0 ) //如果中垂线与火车行进路线平行
                            continue;
                        Point tmp = GetLineIntersection( train.s, train.v, L[i][j].s, L[i][j].v );  //求交点//交点到形成中垂线的线段的其中一个端点的距离
                        double limit = Length( GSM[i] - tmp );
                        Point st = city[a], ed = city[b];
                        if ( ed < st ) swap( st, ed );
    
                        if ( check( st, ed, tmp ) )  //如果在线段上
                        {
                            if ( check2( limit, tmp ) ) //如果确实在这点交换基站
                                ++huan;
                        }
                    }
                printf( "%d
    ", huan );
            }
        }
        return 0;
    }
  • 相关阅读:
    java的构造方法 java程序员
    No result defined for action cxd.action.QueryAction and result success java程序员
    大学毕业后拉开差距的真正原因 java程序员
    hibernate的回滚 java程序员
    验证码 getOutputStream() has already been called for this response异常的原因和解决方法 java程序员
    浅谈ssh(struts,spring,hibernate三大框架)整合的意义及其精髓 java程序员
    你平静的生活或许会在某个不可预见的时刻被彻底打碎 java程序员
    Spring配置文件中使用ref local与ref bean的区别. 在ApplicationResources.properties文件中,使用<ref bean>与<ref local>方法如下 java程序员
    poj1416Shredding Company
    poj1905Expanding Rods
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3241886.html
Copyright © 2020-2023  润新知