zoukankan      html  css  js  c++  java
  • 牛客网暑期ACM多校训练营(第三场) J Distance to Work 计算几何求圆与多边形相交面积模板

    链接:https://www.nowcoder.com/acm/contest/141/J
    来源:牛客网

    Eddy has graduated from college. Currently, he is finding his future job and a place to live. Since Eddy is currently living in Tien-long country, he wants to choose a place inside Tien-long country to live. Surprisingly, Tien-long country can be represented as a simple polygon on 2D-plane. More surprisingly, Eddy can choose any place inside Tien-long country to live. The most important thing Eddy concerns is the distance from his place to the working place. He wants to live neither too close nor too far to the working place. The more specific definition of "close" and "far" is related to working place.

    Eddy has M choices to work in the future. For each working place, it can be represented as a point on 2D-plane. And, for each working place, Eddy has two magic parameters P and Q such that if Eddy is going to work in this place, he will choose a place to live which is closer to the working place than portion of all possible living place choices.

    Now, Eddy is wondering that for each working place, how far will he lives to the working place. Since Eddy is now busy on deciding where to work on, you come to help him calculate the answers.

    For example, if the coordinates of points of Tien-long country is (0,0), (2,0), (2, 2), (0, 2) in counter-clockwise order. And, one possible working place is at (1,1) and P=1, Q=2. Then, Eddy should choose a place to live which is closer to (1, 1) than half of the choices. The distance from the place Eddy will live to the working place will be about 0.7978845608.

    输入描述:

    The first line contains one positive integer N indicating the number of points of the polygon representing Tien-long country.
    Each of following N lines contains two space-separated integer (x

    i

    , y

    i

    ) indicating the coordinate of i-th points. These points is given in clockwise or counter-clockwise order and form the polygon.
    Following line contains one positive integer M indicating the number of possible working place Eddy can choose from.
    Each of following M lines contains four space-separated integer x

    j

    , y

    j

    , P, Q, where (x

    j

    , y

    j

    ) indicating the j-th working place is at (x

    j

    , y

    j

    ) and magic parameters is P and Q.
    3 ≤ N ≤ 200
    1 ≤ M ≤ 200
    1 ≤ P < Q ≤ 200
    |x

    i

    |, |y

    i

    |, |x

    j

    |, |y

    j

    | ≤ 103
    It's guaranteed that the given points form a simple polygon.

    输出描述:

    Output M lines. For i-th line, output one number indicating the distance from the place Eddy will live to the i-th working place.

    Absolutely or relatively error within 10-6
     will be considered correct.

    示例1

    输入

    复制
    4
    0 0
    2 0
    2 2
    0 2
    1
    1 1 1 2

    输出

    复制
    0.797884560809
    示例2

    输入

    复制
    3
    0 0
    1 0
    2 1
    2
    0 0 1 2
    1 1 1 3

    输出

    复制
    1.040111537176
    0.868735603376

    题意:给你一个多变形,再给你几个圆心点,问每个圆心点的半径为多少时,圆的面积为多边形面积的(1-p/q)
    

       分析:一个多边形与圆相交的模板题,求圆心点半径的时候二分就行,限制二分次数保证精度

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    
    using namespace std;
    
    const double eps = 1e-9;
    const double PI = acos(-1.0);
    
    
    int dcmp(double x)
    {
        if( x > eps ) return 1;
        return x < -eps ? -1 : 0;
    }
    
    struct Point
    {
        double x,y;
        Point()
        {
            x = y = 0;
        }
        Point(double a,double b)
        {
            x = a;
            y = b;
        }
        inline void input()
        {
            scanf("%lf%lf",&x,&y);
        }
        inline Point operator-(const Point &b)const
        {
            return Point(x - b.x,y - b.y);
        }
        inline Point operator+(const Point &b)const
        {
            return Point(x + b.x,y + b.y);
        }
        inline Point operator*(const double &b)const
        {
            return Point(x * b,y * b);
        }
        inline double dot(const Point &b)const
        {
            return x * b.x + y * b.y;
        }
        inline double cross(const Point &b,const Point &c)const
        {
            return (b.x - x) * (c.y - y) - (c.x - x) * (b.y - y);
        }
        inline double Dis(const Point &b)const
        {
            return sqrt((*this-b).dot(*this-b));
        }
        inline bool InLine(const Point &b,const Point &c)const  //三点共线
        {
            return !dcmp(cross(b,c));
        }
        inline bool OnSeg(const Point &b,const Point &c)const  //点在线段上,包括端点
        {
            return InLine(b,c) && (*this - c).dot(*this - b) < eps;
        }
        int operator^(const Point &b) const
        {
            return y*b.x-x*b.y;
        }
    };
    
    inline double min(double a,double b)
    {
        return a < b ? a : b;
    }
    inline double max(double a,double b)
    {
        return a > b ? a : b;
    }
    inline double Sqr(double x)
    {
        return x * x;
    }
    inline double Sqr(const Point &p)
    {
        return p.dot(p);
    }
    
    Point LineCross(const Point &a,const Point &b,const Point &c,const Point &d)
    {
        double u = a.cross(b,c), v = b.cross(a,d);
        return Point((c.x * v + d.x * u) / (u + v), (c.y * v + d.y * u) / (u + v));
    }
    
    double LineCrossCircle(const Point &a,const Point &b,const Point &r,
                           double R,Point &p1,Point & p2)
    {
        Point fp = LineCross(r, Point(r.x+a.y-b.y, r.y+b.x-a.x), a, b);
        double rtol = r.Dis(fp);
        double rtos = fp.OnSeg(a, b) ? rtol : min(r.Dis(a), r.Dis(b));
        double atob = a.Dis(b);
        double fptoe = sqrt(R * R - rtol * rtol) / atob;
        if( rtos > R - eps ) return rtos;
        p1 = fp + (a - b) * fptoe;
        p2 = fp + (b - a) * fptoe;
        return rtos;
    }
    
    double SectorArea(const Point &r,const Point &a,const Point &b,double R)  //不大于180度扇形面积,r->a->b逆时针
    {
        double A2 = Sqr(r - a), B2 = Sqr(r - b), C2 = Sqr(a - b);
        return R * R * acos( (A2 + B2 - C2) * 0.5 / sqrt(A2) / sqrt(B2)) * 0.5;
    }
    
    double TACIA(const Point &r,const Point &a,const Point &b,double R)
    {
        double adis = r.Dis(a), bdis = r.Dis(b);
        if( adis < R + eps && bdis < R + eps )
            return r.cross(a, b) * 0.5;
        Point ta, tb;
        if( r.InLine(a,b) ) return 0.0;
        double rtos = LineCrossCircle(a, b, r, R, ta, tb);
        if( rtos > R - eps )
            return SectorArea(r, a, b, R);
        if( adis < R + eps )
            return r.cross(a, tb) * 0.5 + SectorArea(r, tb, b, R);
        if( bdis < R + eps )
            return r.cross(ta, b) * 0.5 + SectorArea(r, a, ta, R);
        return r.cross(ta, tb) * 0.5 + SectorArea(r, tb, b, R) + SectorArea(r, a, ta, R);
    }
    
    const int MAXN  = 505;
    Point p[MAXN];
    
    double SPICA(int n,Point r,double R)
    {
        int i;
        double ret = 0, if_clock_t;
        for( i = 0 ; i < n ; ++i )
        {
            if_clock_t = dcmp(r.cross(p[i], p[(i + 1) % n]));
            if( if_clock_t < 0 )
                ret -= TACIA(r, p[(i + 1) % n], p[i], R);
            else ret += TACIA(r, p[i], p[(i + 1) % n], R);
        }
        return fabs(ret);
    }
    
    
    double ComputePolygonArea(int n)
    {
        double sum=0;
        for(int i=1;i<=n-1;i++)
            sum+=(p[i]^p[i-1]);
        sum+=(p[0]^p[n-1]);
        return fabs(sum/2);
    }
    
    int main()
    {
        int n,m;
        scanf("%d",&n);///多边形n个顶点
        for(int i = 0 ; i < n ; ++i )///顶点坐标
            p[i].input();
        double polyArea = ComputePolygonArea(n);///计算多边形面积
        scanf("%d",&m);
        while(m--)
        {
    
            Point circle;
            circle.input(); ///圆心坐标
            int pp,qq;
            scanf("%d%d",&pp,&qq);
            double area = (1.0-(double)pp/qq)*polyArea;
    
            ///二分圆的半径
          //  printf("%f
    ",area);
            double l =0, r=1e18;
            ///固定二分次数
            for(int i=1;i<300;i++){
                double mid = (l+r)/2.0;
                double insection = SPICA(n,circle,mid); ///圆与多边形交的面积
                if(insection>area){
                    r = mid-eps;
                }else{
                    l = mid;
                }
            }
            printf("%.10lf
    ",r);
        }
        return 0;
    }
    

      

    彼时当年少,莫负好时光。
  • 相关阅读:
    第七章 Net 5.0 快速开发框架 YC.Boilerplate -- 数据层ORM 设计
    第六章 Net 5.0 快速开发框架 YC.Boilerplate -- 代码生成和数据库表生成
    第五章 Net 5.0 快速开发框架 YC.Boilerplate -- 缓存模块
    第四章 Net 5.0 快速开发框架 YC.Boilerplate-- 动态WebApi
    第三章 Net 5.0 快速开发框架 YC.Boilerplate-- 多租户介绍
    第二章 Net 5.0 快速开发框架 YC.Boilerplate-- 快速入门
    第一章 Net 5.0 快速开发框架 YC.Boilerplate--框架介绍
    【雕爷学编程】Arduino动手做(90)---4X4矩阵薄膜键盘模块
    【雕爷学编程】Arduino动手做(89)---8位双向电平转换模块
    多端自动化运行:pc+android+ios+小程序 均可
  • 原文地址:https://www.cnblogs.com/l609929321/p/9379579.html
Copyright © 2011-2022 走看看