2018牛客网暑期ACM多校训练第三场 J-Distance to Work

题目链接:J-Distance to Work

思路分析: 板子题,简单多边形和圆面积交 + 二分

 

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;


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

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

struct Point{
    double x,y;
    Point(){}
    Point(double x, double y):x(x),y(y){}
};

typedef Point Vector;
Vector operator +(Vector A,Vector B) {return Vector(A.x+B.x,A.y+B.y); }
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }
Vector operator *(Vector A,double p) {return Vector(A.x*p,A.y*p); }
double Dot(Vector A,Vector B) {return A.x*B.x + A.y*B.y;}
double Cross(Vector A, Vector B) {return A.x*B.y-A.y*B.x;}
double Length(Vector A) {return sqrt(Dot(A,A)); }
double sqr(double x) {return x*x;}

double Triangle_cross_Circle(Point A,Point B, Point C, double r){
      double a,b,c,x,y;
      double s = 0.5*Cross(A-C,B-C);

      a = Length(B-C);
      b = Length(A-C);
      c = Length(A-B);

      if (a <= r && b <= r) return s;
      else if (a<r && b>=r) {
         x  = (Dot(A-B,C-B) + sqrt(c*c*r*r - sqr(Cross(A-B,C-B))))/c;
         return asin(s*(c-x)*2.0/c/b/r)*r*r*0.5 + s*x/c;
      }
      else if (a >= r && b<r) {
         y  = (Dot(B-A,C-A) + sqrt(c*c*r*r - sqr(Cross(B-A,C-A))))/c;
         return asin(s*(c-y)*2.0/c/a/r)*r*r*0.5 + s*y/c;
      }
      else {
         if (fabs(2.0*s) >= r*c || Dot(B-A,C-A) <= 0 || Dot(A-B,C-B) <= 0) {
            if (Dot(A-C,B-C) < 0) {
                if (Cross(A-C,B-C) < 0) return (-PI - asin(s*2.0/a/b))*r*r*0.5;
                else return (PI - asin(s*2.0/a/b))*r*r*0.5;
            }
            else return asin(s*2.0/a/b)*r*r*0.5;
         }
         else {
            x = (Dot(A-B,C-B) + sqrt(c*c*r*r - sqr(Cross(A-B,C-B))))/c;
            y = (Dot(B-A,C-A) + sqrt(c*c*r*r - sqr(Cross(B-A,C-A))))/c;
            return (asin(s*(1-x/c)*2/r/b) + asin(s*(1-y/c)*2/r/a))*r*r*0.5 + s*((y+x)/c-1);
         }
      }
}

const int maxn = 1000;
int n,m;
Point p[maxn];

double check(int n, Point cir, double r){
    double res = 0.0;
    for (int i=0; i<n; ++i) res += Triangle_cross_Circle(p[i],p[i+1],cir,r);
    return fabs(res);
}



int main(){
    while (scanf("%d",&n) == 1) {
        for (int i=0; i<n; ++i) scanf("%lf%lf",&p[i].x,&p[i].y);
        p[n] = p[0];

        double poly_area = 0.0;
        for (int i=0; i<n; ++i) poly_area += Cross(p[i],p[i+1]);
        poly_area = fabs(poly_area)*0.5;

        scanf("%d",&m);
        while (m--) {
            Point cir;
            double a,b;
            scanf("%lf%lf%lf%lf",&cir.x,&cir.y,&a,&b);

            a = b-a;
            double l = 0, r = 1e7;
            for (int i=0; i<60; ++i) {
                double mid = (l+r)*0.5;
                if (check(n,cir,mid)*b > poly_area*a) r = mid;
                else l = mid;
            }
            printf("%.10f\n",l);
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值