【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);
}
}