L. Machining Disc Rotors

题目让我们求一个圆心位于\left ( 0,0\right )的圆(后面都用c表示这个圆的圆心)被n个形状为圆的切割臂切割之后剩余图形(可能是非凸的)的直径,也就是就最远的两个点。很容易想到的是求出所有的交点,枚举任意两个交点之间的距离取最大值,但是还可能存在最远距离为直径的情况。如果一个交点关于点c对称的点没有被切割掉,那么最远的距离就是圆的直径。

求所有的交点很简单,关键在怎么判断最远距离为直径的情况,也就是求是否存在一个交点关于点c对称的点不被任何一个机械臂包含。

#include <bits/stdc++.h>
#define fixed(s) fixed<<setprecision(12)<<s

using namespace std;
typedef long long ll;
typedef array<int, 3> Arr;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

const int N = 2e5 + 7;

//浮点数比较 
const double eps = 1e-8;
int dcmp(double x)  // 符号函数
{
    if (fabs(x) < eps) return 0; //为0
    if (x < 0) return -1; //负数 
    return 1; //正数 
}
int cmp(double x, double y)  // 比较函数
{
    if (fabs(x - y) < eps) return 0; //相等 
    if (x < y) return -1;
    return 1; 
}

struct Point{
    double x, y;
};

Point operator+ (Point a, Point b){
    return {a.x + b.x, a.y + b.y};
}
Point operator- (Point a, Point b){
    return {a.x - b.x, a.y - b.y};
}
double operator* (Point a, Point b){
    return a.x * b.x + a.y * b.y;
}
double operator^ (Point a, Point b){
    return a.x * b.y - a.y * b.x;
}
bool operator< (Point a, Point b){
	if (a.x == b.x) return a.y < b.y;
	return a.x < b.x;
}
bool operator == (Point a, Point b){
	return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}

//两点的距离 
double get_dist(Point a, Point b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}
double cross(Point a, Point b){
    return a.x * b.y - a.y * b.x;
}
//计算向量c在向量b的什么方向,也可以计算向量ab和ac构成的平行四边形有向面积 
double area(Point a, Point b, Point c)
{
    return cross(b - a, c - a);
}
//计算向量a的长度 
double get_length(Point a)
{
    return sqrt(a * a);
}
//计算向量a和b的夹角 
double get_angle(Point a, Point b)
{
    return acos(a * b / get_length(a) / get_length(b));
}

struct Circle{
    Point c; double r;
    Point pnt(double a)
    {
        return {c.x+cos(a)*r,c.y+sin(a)*r};
    }
};

double Angle(Point v)
{
    return atan2(v.y,v.x);
}

//求两个圆的交点 也可以求交点个数
void getCircleCircleIntersection(Circle c1,Circle c2,vector<Point> &sol)
{
    double d = get_length(c1.c-c2.c);
    if(dcmp(d) == 0) return;
    if(dcmp(c1.r + c2.r - d) < 0) return;
    if(dcmp(fabs(c1.r - c2.r) - d) > 0) return;
    double a = Angle(c2.c - c1.c);
    double da = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    Point p1 = c1.pnt(a - da), p2 = c1.pnt(a + da);
    sol.push_back(p1);
    if(p1 == p2) return;
    sol.push_back(p2);
}

void solve(int id){
    int n, R;
    cin >> n >> R;
    Circle C = {{0, 0}, R};
    vector<Circle> p(n);
    vector<Point> res; //存交点
    for (int i = 0; i < n; i++){
        cin >> p[i].c.x >> p[i].c.y >> p[i].r;
    }
    for (int i = 0; i < n; i++){
        getCircleCircleIntersection(C, p[i], res);
    }

    auto check = [&](Point k){
        Point p0 = Point{0, 0} - k; //求出k关于圆心对称的点
        for (int i = 0; i < n; i++){
            //如果p0被圆p[i]包含则p0到到p[i]的圆心距离小于p[i]半径
            if ((p[i].c - p0) * (p[i].c - p0) < p[i].r * p[i].r) return false;
        }
        return true;
    };

    int sz = res.size();
    for (int i = 0; i < sz; i++){
        if (check(res[i])){
            cout << "Case #" << id <<": ";
            cout << fixed(2.0 * C.r) << '\n';
            return;
        }
    }

    double ans = 0;
    for (int i = 0; i < sz; i++){
        for (int j = i + 1; j < sz; j++){
            ans = max(ans, get_dist(res[i], res[j]));
        }
    }
    cout << "Case #" << id <<": ";
    cout << fixed(ans) << '\n';
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T = 1;
    cin >> T;
    for (int i = 1; i <= T; i++){
        solve(i);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值