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

Problem J. Distance to Work

Input file: standard input
Output file: standard output
Time limit: 2 seconds
Memory limit: 256 mebibytes

链接: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.

Input

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 (xi, yi) 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 xj, yj, P, Q, where (xj, yj) indicating the j-th working place is at (xj, yj) and magic parameters is P and Q.

3 ≤ N ≤ 200
1 ≤ M ≤ 200
1 ≤ P < Q ≤ 200
|xi|, |yi|, |xj|, |yj| ≤ 1000
It’s guaranteed that the given points form a simple polygon.

Output

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.

Sample InputSample Output
4
0 0
2 0
2 2
0 2
1
1 1 1 2
0.797884560809
3
0 0
1 0
2 1
2
0 0 1 2
1 1 1 3
1.040111537176
0.868735603376


计算几何,二分半径之后套套板子。

记录这题的原因是,比赛的时候eps调太大了没有过,调小到1e-8反而过了。—-玄学调参!


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include <iomanip>
 typedef long double ld;
using namespace std;

const ld eps = 1e-8;
const ld PI = acos(-1.0);

int dcmp(ld x){
    if( x > eps ) return 1;
    return x < -eps ? -1 : 0;
}

struct Point{
    ld x,y;
    Point(){
        x = y = 0;
    }
    Point(ld a,ld 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 ld &b)const{
        return Point(x * b,y * b);
    }
    inline Point operator/(const ld &b)const{
        return Point(x / b,y / b);
    }
    inline ld dot(const Point &b)const{
        return x * b.x + y * b.y;
    }
    inline ld cross(const Point &b,const Point &c)const{
        return (b.x - x) * (c.y - y) - (c.x - x) * (b.y - y);
    }
    inline ld 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;
    }
};

inline ld min(ld a,ld b){
    return a < b ? a : b;
}
inline ld max(ld a,ld b){
    return a > b ? a : b;
}
inline ld Sqr(ld x){
    return x * x;
}
inline ld Sqr(const Point &p){
    return p.dot(p);
}

Point LineCross(const Point &a,const Point &b,const Point &c,const Point &d){
    ld 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));
} 

ld LineCrossCircle(const Point &a,const Point &b,const Point &r,
                               ld R,Point &p1,Point & p2){
    Point fp = LineCross(r , Point(r.x+a.y-b.y , r.y+b.x-a.x) , a , b);
    ld rtol = r.Dis(fp);
    ld rtos = fp.OnSeg(a , b) ? rtol : min(r.Dis(a) , r.Dis(b));
    ld atob = a.Dis(b);
    ld 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;
}

ld SectorArea(const Point &r,const Point &a,const Point &b,ld R){ 
    ld 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;
}

ld TACIA(const Point &r,const Point &a,const Point &b,ld R){
    ld 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;
    ld 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];

ld SPICA(int n,Point r,ld R){
    int i;
    ld 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);
}

int main(){
    int n,i;
    Point sum=Point(0,0);
    scanf("%d",&n);
    for( i = 0 ; i < n ; ++i ) {
        p[i].input();
        sum=sum+p[i];
    }
    sum=sum/n;
    ld tot=0;
    for (i=0;i<n-1;i++) {
        tot+=sum.cross(p[i],p[i+1]);
    }
    tot+=sum.cross(p[n-1],p[0]);
    tot=fabs(tot/2.0L);
    int m;
    scanf("%d",&m);
    while (m--) {
        Point circle;
        circle.input(); 
        ld P,Q;
        cin >> P >> Q;
        ld R;
        ld l,r,mid;
        l=0;r=1500000;
        while (fabs(l-r)>eps) {
            mid=R=(l+r)/2.0L;
            ld size=SPICA(n,circle,R);
            if (size*Q>(Q-P)*tot) r=mid; else l=mid;
        }
        cout << setiosflags(ios::fixed) << setprecision(12);
        cout << (l+r)/2.0L << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值