【2018牛客多校round3 J】Distance to Work

题意

给一个简单多边形,多边形内有一个点A,要求另外一个点B,在至少有P/Q(P<Q) 个点距离大于点B到点A的距离的前提下,点B到点A的距离最大,求这个距离

分析

以A点为圆心AB距离为半径画圆,圆外的点距离A都比B距离A大
二分圆的半径,求圆和多边形面积的交,这些点都是比B到A距离小的,找到恰好面积为多边形面积(Q-P)/P倍的半径,得到最后的答案

代码

#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);
    }
}
posted @ 2018-07-27 20:15  Greenty  阅读(134)  评论(0编辑  收藏  举报