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

题意:找出以工作地点为圆心的圆交多边形的面积比上多边形面积为(1-(P/Q)).

题解:贴一个圆交多边形面积的模版,以及求多边形面积的模版,然后二分一下半径即可

#include"bits/stdc++.h"
using namespace std;
const int MX = 222;

const double eps = 1e-12;
const double PI = acos( -1.0 ) ;
inline double sqr( double x ){ return x * x ; }
inline int dcmp( double x ){
    if ( fabs(x) < eps ) return 0 ;
    return x > 0? 1 : -1 ;
}

struct Point{
    double x , y ;
    Point(){}
    Point( double _x , double _y ): x(_x) , y(_y) {}
    void input() { scanf( "%lf%lf" ,&x ,&y ); }
//    double norm() { return sqrt( sqr(x) + sqr(y) ); }

    friend Point operator + ( const Point &a , const Point &b ) { return Point( a.x + b.x , a.y + b.y ) ; }
    friend Point operator - ( const Point &a , const Point &b ) { return Point( a.x - b.x , a.y - b.y ) ; }
    friend Point operator * ( const Point &a , const double &b ) { return Point( a.x * b , a.y * b ) ; }
    friend Point operator * ( const double &a , const Point &b ) { return Point( b.x * a , b.y * a ) ; }
    friend Point operator / ( const Point &a , const double &b ) { return Point( a.x / b , a.y / b ) ; }
    friend bool operator == ( const Point &a , const Point &b ) { return dcmp( a.x - b.x ) == 0 && dcmp( a.y - b.y ) == 0 ; }

    bool operator < ( const Point &a )const{
        return ( dcmp( x - a.x ) < 0 ) || ( dcmp( x - a.x ) == 0 && dcmp( y - a.y ) < 0 ) ;
    }
};
typedef Point Vector;
double Dot( Point a , Point b ) { return a.x * b.x + a.y * b.y ; }
double Cross( Point a , Point b ) { return a.x * b.y - a.y * b.x ; }
double Length(Vector A) { return sqrt(Dot(A,A)) ; }

int n,m;
Point p[205];

int CircleInterLine( Point a, Point b, Point o, double r, Point *p )
{
    Point p1 = a - o ;
    Point d = b - a ;
    double A = Dot( d, d ) ;
    double B = 2 * Dot( d, p1 ) ;
    double C = Dot( p1, p1 ) - sqr(r) ;

    double delta = sqr(B) - 4*A*C ;
    if ( dcmp(delta) < 0 ) return 0 ;//相离
    if ( dcmp(delta) == 0 ) { //相切
        double t = -B / (2*A) ; // 0 <= t <= 1说明交点在线段上
        if ( dcmp( t - 1 ) <= 0 && dcmp( t ) >= 0 ) {
            p[0] = a + t * d ;
            return 1 ;
        }
    }
    if ( dcmp(delta) > 0 ) { //相交
        double t1 = ( -B - sqrt(delta) ) / (2*A) ;
        double t2 = ( -B + sqrt(delta) ) / (2*A) ; //0 <= t1, t2 <= 1说明交点在线段上
        int k = 0 ;
        if ( dcmp( t1 - 1 ) <= 0 && dcmp( t1 ) >= 0 )
            p[k++] = a + t1 * d ;
        if ( dcmp( t2 - 1 ) <= 0 && dcmp( t2 ) >= 0 )
            p[k++] = a + t2 * d ;
        return k ;
    }
    return 0;
}
double Triangle_area( Point a, Point b )
{
    return fabs( Cross( a , b ) ) / 2.0  ;
}
double Sector_area( Point a, Point b, double r )
{
    double ang = atan2( a.y , a.x ) - atan2( b.y, b.x  ) ;
    while ( ang <= 0 ) ang += 2.0 * PI ;
    while ( ang > 2.0 * PI ) ang -= 2.0 * PI ;
    ang = min( ang, 2.0*PI - ang ) ;
    return sqr(r) * ang/2.0 ;
}
double calc( Point a , Point b , double r )
{
    Point pi[2] ;
    if ( dcmp( Length(a) - r ) < 0 ) {
        if ( dcmp( Length(b) - r ) < 0 ) {
            return Triangle_area( a, b ) ;
        }
        else {
            CircleInterLine( a, b, Point(0,0), r, pi) ;
            return Sector_area( b, pi[0], r ) + Triangle_area( a, pi[0] ) ;
        }
    }
    else {
        int cnt = CircleInterLine( a, b, Point(0,0), r, pi ) ;
        if ( dcmp( Length(b) - r ) < 0 ) {
            return Sector_area( a, pi[0],r ) + Triangle_area( b, pi[0] ) ;
        }
        else {
            if ( cnt == 2 )
                return Sector_area( a, pi[0],r ) + Sector_area( b, pi[1], r ) + Triangle_area( pi[0], pi[1]) ;
            else
                return Sector_area( a, b, r ) ;
        }
    }
}
double area_CircleAndPolygon( Point *p , int n , Point o , double r )
{
    double res = 0 ;
    p[n] = p[0] ;
    for ( int i = 0 ; i < n ; i++ ) {
        int tmp = dcmp( Cross( p[i] - o , p[i+1] - o ) ) ;
        if ( tmp )
            res += tmp * calc( p[i] - o , p[i+1] - o , r ) ;
    }
    return fabs( res ) ;
}

double PolygonArea(Point *p,int n) {
    double area=0;
    for(int i=1; i < n-1; i++)
        area+=Cross(p[i]-p[0],p[i+1]-p[0]);
    return fabs(area/2);
}


void work(long double &sums, Point o,double P, double Q)
{

    long double l = 0, r = 1e4;
    for(int i = 0; i < 100; i++){
        long double mid = (l+r)/2;
        long double ss = area_CircleAndPolygon(p,n,o,mid);
        if((Q-P)*sums > ss*Q) l = mid;
        else r = mid;
    }
    double ans = (l+r)/2;
    printf("%.12f\n",ans);
}

int main()
{
#ifdef LOCAL
    freopen("input.txt","r",stdin);
#endif // LOCAL
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    long double sums = PolygonArea(p,n);
    scanf("%d",&m);
    for(int i = 1; i <= m; i++){
        double x,y,P,Q;
        scanf("%lf %lf %lf %lf",&x,&y,&P,&Q);
        work(sums,Point(x,y), P,Q);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值