cf-gym103176 D. Drawing Circles(计算几何&精度&数学&优先队列)

题意(可以直接看代码部分,有题意翻译,os:有点简略)

在这里插入图片描述

在这里插入图片描述

代码&题解啥的

/*
题目链接:https://codeforces.com/gym/103176/problem/D
题意:最开始给两个大圆,按条件依次添加n<=3e5个圆,求每个圆的半径。
    条件:
        1. 所有圆(包括两个大圆)都必须与x轴相切。
        2. 每次添加的圆(自然,除了两个大圆)都必须与之前的某两个圆相切而且所有圆都没有重合部分。
        3. 每次添加所有满足条件的圆中半径最大的圆,如果最大半径有多个,那就优先添加最右边的圆。
    最后依次打印所有圆的半径(误差不能超过1e-6)。
题解:优先队列维护所有“区间”,每次取出一个区间,加入两个“区间”。
    eps=1e-8可以过,eps=1e-6要凉。
*/
#include <bits/stdc++.h>
#define int long long
// #define double long double
using namespace std;
const int N = 3e5 + 5;
const double eps = 1e-8;
int sgn(double x) {
    if (fabs(x) < eps) return 0;
    if (x > 0) return 1;
    return -1;
}
double r1, r2;
vector<double> v;
int n;
//小圆半径
double C(double r1, double r2) {
    return (r1 * r2) / (r1 + r2 + 2.0 * sqrt(r1 * r2));
}
double X(double x, double r1) { return sqrt(4.0 * r1 * x); }
//圆的x坐标及半径
struct Point {
    double x, r;
    Point(double x = 0.0, double r = 0.0) : x(x), r(r) {}
} p1, p2, p3;
//“区间”
struct node {
    Point L, R;
    node(Point L = Point(0.0, 0.0), Point R = Point(0.0, 0.0)) : L(L), R(R) {}
    bool operator<(const node &b) const {
        double x1 = C(L.r, R.r), x2 = C(b.L.r, b.R.r);
        if (sgn(x1 - x2) == 0) return sgn(L.x - b.L.x) < 0;
        return sgn(x1 - x2) < 0;
    }
};
priority_queue<node> q;
signed main() {
    cin >> r1 >> r2 >> n;
    double x1, x2, x3, x = C(r1, r2);
    v.push_back(x);

    x1 = 0.0, x2 = x1 + X(x, r1), x3 = x1 + X(x, r1) + X(x, r2);
    p1 = Point(x1, r1), p2 = Point(x2, x), p3 = Point(x3, r2);
    q.push(node(p1, p2));
    q.push(node(p2, p3));
    while (v.size() < n) {
        node now = q.top();
        q.pop();
        Point L = now.L, R = now.R;
        x = C(L.r, R.r);
        v.push_back(x);
        p2 = Point(L.x + X(x, L.r), x);
        q.push(node(L, p2));
        q.push(node(p2, R));
    }
    for (auto i : v) printf("%.6lf ", i);
    return 0;
}
/*
9 4 4
1.44 0.734694 0.5625 0.444444

10 10 1
2.5000000000

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值