Distance to Work (牛客多校) (圆和简单多边形相交面积 + 二分半径)

发布时间 2023-06-28 12:52:41作者: VxiaohuanV
#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-9;            //浮点数精度控制
#define Vector point
#define Point point
const double PI = acos(-1);
struct Point{
    double x,y;
    Point(double x=0,double y=0) :x(x),y(y){}
    friend Vector operator + (Vector A,Vector B){ return Vector(A.x + B.x , A.y + B.y);}
    friend Vector operator - (Point A,Point B){ return Vector(A.x - B.x , A.y - B.y);}
    friend Vector operator * (Vector A,double p) {return Vector(A.x*p , A.y*p);}
    friend Vector operator / (Vector A,double p) {return Vector(A.x/p,A.y/p);}
    friend bool operator < (const Point &a,const Point &b){
    return a.x< b.x || ( a.x == b.x && a.y < b.y);
    }
};
int dcmp(double k){
    return k < -eps ?-1:k>eps?1:0;
}
double sqr(double k){return k*k;}
double mysqrt(double n){ return sqrt(max(0.0,n));}
double cross(Vector A,Vector B){return A.x*B.y - A.y*B.x;}
double dot(Vector A,Vector B){return A.x*B.x + A.y*B.y;}
double abs(Point o){return sqrt(dot(o,o));}
point _a[205],o;
int P,Q;
int n;
double r;
double ALL;
void circle_cross_line(Point a,Point b,Point o,double r,Point ret[],int &num){
    double x0 = o.x,y0 = o.y;
    double x1 = a.x,y1 = a.y;
    double x2 = b.x,y2 = b.y;
    double dx = x2 - x1,dy = y2-y1;
    double A = dx*dx +dy*dy;
    double B = 2*dx*(x1-x0)+2*dy*(y1-y0);
    double C = sqr(x1-x0)+sqr(y1-y0)-sqr(r);
    double delta = B*B - 4*A*C;
    num = 0;
    if(dcmp(delta)>=0){
    double t1 = (-B-mysqrt(delta))/(2*A);
    double t2 = (-B+mysqrt(delta))/(2*A);
    if(dcmp(t1-1)<=0 && dcmp(t1)>=0){
        ret[num++] = Point(x1+t1*dx , y1 + t1*dy);
    }
    if(dcmp(t2-1)<=0 && dcmp(t2)>=0){
        ret[num++] = Point(x1 + t2*dx,y1+t2*dy);
    }
    }

}
double sector_area(point a,point b){
    double theta = atan2(a.y,a.x) - atan2(b.y,b.x);
    while(theta <=0) theta+=2*PI;
    while(theta > 2*PI) theta -= 2*PI;
    theta = min (theta,2*PI - theta);
    return r*r *theta / 2;
}
double calc(Point a,Point b){
    Point p[2];
    int num = 0;
    int ina = dcmp(abs(a)-r)<0;
    int inb = dcmp(abs(b)-r)<0;
    if(ina){
    if(inb){
        return fabs(cross(a,b))/2.0;
    }else{
        circle_cross_line(a,b,Point(0,0),r,p,num);
        return sector_area(b,p[0])+fabs(cross(a,p[0]))/2.0;
    }
    }else{
    if(inb) {
        circle_cross_line(a,b,Point(0,0),r,p,num);
        return sector_area(p[0],a)+fabs(cross(p[0],b))/2.0;
    }else{
        circle_cross_line(a,b,Point(0,0),r,p,num);
        if(num == 2){
        return sector_area(a,p[0]) + sector_area(p[1],b)
            + fabs(cross(p[0],p[1]))/2.0;
        }else {
        return sector_area(a,b);
        }

    }
    }
}
double area(){
    double ret = 0;
    for(int i = 1;i<=n;i++){
    int sgn = dcmp(cross(_a[i],_a[i+1]));
    if(sgn!=0) ret+=sgn * calc(_a[i],_a[i+1]);
    }
    return abs(ret);
}
bool check()
{
    double are = area();
    if(dcmp(are - ALL)<0) return false;
    return true;
}
Point __a[206];
double PolygonArea(){
    double area = 0;
    for(int i = 2;i<n;i++)
    {
    area+=cross(__a[i] - __a[1],__a[i+1] - __a[1]);
    }    
    return fabs(area*0.5);
}
int main()
{
    cin>>n;
    for(int i = 1;i<=n;i++) cin>>__a[i].x>>__a[i].y;
    __a[n+1] = __a[1];
    n++;
    int m;cin>>m;
    double all = PolygonArea();
    while(m--)
    {
         cin>>o.x>>o.y>>P>>Q;
        for(int i = 1;i<=n;i++) _a[i] = __a[i] - o;
        P = Q-P;
        ALL = P*all/Q;
        double L = 0,R = 5000000;
        while(dcmp(L-R)!=0)
        {
            r =(L+R)/2.0;
            if(check()) R = r;
            else L = r;
        }
        printf("%.10f\n",L);
    }
}
模板代码