牛客网暑期ACM多校训练营(第三场)J:Distance to Work(计算几何+二分)

链接:https://www.nowcoder.com/acm/contest/141/J

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld
题目描述
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 PQ P Q 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 N lines contains two space-separated integer (xi,yi) ( 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 M indicating the number of possible working place Eddy can choose from.
Each of following M lines contains four space-separated integer xj,yj,P,Q, x j , y j , P , Q , where (xj,yj) ( x j , y j ) indicating the j-th working place is at (xj,yj) ( x j , y j ) and magic parameters is P and Q.

3 ≤ N ≤ 200
1 ≤ M ≤ 200
1 ≤ P < Q ≤ 200
|xi|,|yi|,|xj|,|yj|103 | x i | , | y i | , | x j | , | y j | ≤ 10 3
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 106 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

思路:对于每个点,二分半径R,求以该点为圆心,半径为R的圆,与简单多边形的相交面积

#include
using namespace std;
const int MAX=1e6+10;
const int MOD=998244353;
const double PI=acos(-1.0);
typedef long long ll;
struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){}
    void show(){cout<<"("<","<")"<300],b[300];
Point operator+(Point A,Point B){return (Point){A.x+B.x,A.y+B.y};}        //向量A+B
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y};}        //向量A-B
Point operator*(Point A,double B){return (Point){A.x*B,A.y*B};}           //向量A*B
Point operator/(Point A,double B){return (Point){A.x/B,A.y/B};}           //向量A/B
double operator*(Point A,Point B){return A.x*B.x+A.y*B.y;}            //向量A B的点积
double operator^(Point A,Point B){return A.x*B.y-A.y*B.x;}            //向量A B的叉积
double cross(Point A,Point B){return A.x*B.y-A.y*B.x;}                //向量A B的叉积
double dis(Point A,Point B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}//A B两点的距离
double dis2(Point A,Point B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);}     //A B两点的距离的平方
double Polyarea(Point *p,int n)   //求多边形面积(任意形状都可)
{
    double area=0;
    for(int i=1;i1;i++)area+=(p[i]-p[0])^(p[i+1]-p[0]);
    return fabs(area/2);
}
double Distoline(Point P,Point A,Point B){return fabs(cross(B-A,P-A))/dis(A,B);}//点P到直线AB距离
Point pverti(Point P,Point A,Point B)//求点P在直线AB上的投影点
{
    double AA=A.y-B.y;
    double BB=-(A.x-B.x);
    double CC=A.y*(A.x-B.x)-A.x*(A.y-B.y);
    Point PP=(Point){P.x-2*AA*(AA*P.x+BB*P.y+CC)/(AA*AA+BB*BB),P.y-2*BB*(AA*P.x+BB*P.y+CC)/(AA*AA+BB*BB)};
    return (PP+P)/2;
}
double slove(Point P,Point A,Point B,double R)
{
    double h=Distoline(P,A,B);
    if(dis2(P,A)<=R*R&&dis2(P,B)<=R*R)return fabs(cross(A-P,B-P))/2;//A B两点均在圆内
    if(dis2(P,A)>R*R)swap(A,B);
    if(dis2(P,A)<=R*R&&dis2(P,B)>R*R)                               //A B两点有一点在圆内
    {
        double angle=(dis2(P,A)+dis2(A,B)-dis2(P,B))/(2*dis(P,A)*dis(A,B));
        angle=acos(angle);
        double C=angle+asin(sin(angle)*dis(P,A)/R);
        double len=sin(C)*R/sin(angle);
        angle=(dis2(P,A)+dis2(P,B)-dis2(A,B))/(2*dis(P,A)*dis(P,B));
        angle=acos(angle)-(PI-C);
        return len*h/2+angle*R*R/2;
    }
    double angle=(dis2(P,A)+dis2(P,B)-dis2(A,B))/(2*dis(P,A)*dis(P,B));//A B两点均在圆外
    double area=acos(angle)*R*R/2;
    Point PP=pverti(P,A,B);
    if(h>=R||cross(PP-P,A-P)*cross(PP-P,B-P)>0)return area;            //线段AB与圆不相交
    return area-(2*acos(h/R)*R*R/2-h*sqrt(R*R-h*h));                   //线段AB与圆相交
}
double cal(int n,Point p,double r)
{
    double tot=0;
    for(int i=0;iif(cross(a[i]-p,a[(i+1)%n]-p)==0)continue;
        double area=slove(p,a[i],a[(i+1)%n],r);
        if(cross(a[i]-p,a[(i+1)%n]-p)>0)tot+=area;
        else tot-=area;
    }
    return fabs(tot);
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;iscanf("%lf%lf",&a[i].x,&a[i].y);
    double sum=Polyarea(a,n);
    int m;
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        int x,y,p,q;
        scanf("%d%d%d%d",&x,&y,&p,&q);
        p=q-p;
        double l=0,r=1e9;
        for(int i=1;i<=100;i++)
        {
            double mid=(l+r)/2;
            if(cal(n,(Point){x*1.0,y*1.0},mid)<=sum*p/q)l=mid;
            else r=mid;
        }
        printf("%.12lf\n",(l+r)/2);
    }
    return 0;
}

你可能感兴趣的:(计算几何)