2013杭州region D HDU 4773

Problem of Apollonius

题意:给定两个圆,告诉半径和圆心,它们是相离的,在这两个圆外给定一个点p,求符合条件:过点p的圆且与已知的两个圆外切的所有圆的总数和它们的圆心坐标和半径。

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4773

直接联立方程求解十分复杂,用圆的反演求解此题(几乎是模板题)

圆的反演:由于反演之后相切关系保持不变,长用作相切圆的处理

好懂的反演圆的介绍
反形圆求法
动图理解
c1 c 1 为原始圆圆心, co c o 为反演中心, c2 c 2 为反型圆圆心
其中反形圆的圆心 c=co+OC2OC1(c1co) c = c o + O C 2 O C 1 ( c 1 − c o )
又有 OC2OC1=r2r1 O C 2 O C 1 = r 2 r 1

注意:不仅要求的是公切线,为了防止出现内切的情况,我们要求的是“外公切线”,并且要使得P点和反形圆的圆心在外公切线的同一侧。

代码:

#include<bits/stdc++.h>
using namespace std;

int t;
const double eps = 1e-9;
const double pi = acos(-1);
int sign(double x) {
    if (fabs(x) < eps) return 0;
    return x > 0 ? 1 : -1;
}
struct point {
    double x, y;
    point(double x = 0, double y = 0) :x(x), y(y) {}
    point operator + (const point &rhs) const {
        return point(x + rhs.x, y + rhs.y);
    }
    point operator - (const point &rhs) const {
        return point(x - rhs.x, y - rhs.y);
    }
    point operator * (const double &rhs) const {
        return point(x * rhs, y * rhs);
    }
    point operator / (const double &rhs) const {
        return point(x / rhs, y / rhs);
    }
    void read() {
        scanf("%lf%lf", &x, &y);
    }
};
double dot(point a, point b) {
    return a.x * b.x + a.y * b.y;
}
double len(point v) {
    return sqrt(dot(v, v));
}
double cross(point a, point b) {
    return a.x * b.y - a.y * b.x;
}
double cross(point A, point B, point C) {
    return (B.x-A.x)*(C.y-A.y) - (B.y-A.y) * (C.x-A.x);
}
struct circle {
    point c;
    double r;
    circle() {}
    circle(point c, double r) :c(c), r(r) {}
    point get_point(double ang) {
        return point(c.x + cos(ang) * r, c.y + sin(ang) * r);
    }
    void read() {
        c.read();
        scanf("%lf", &r);
    }
};

circle get_cir(point p1, point p2, point p3) {
    double x1 = p1.x, x2 = p2.x, x3 = p3.x;
    double y1 = p1.y, y2 = p2.y, y3 = p3.y;
    double a = x1 - x2, b = y1 - y2, c = x1 - x3, d = y1 - y3;
    double e = ((x1 * x1 - x2 * x2) + (y1 * y1 - y2 * y2)) / 2;
    double f = ((x1 * x1 - x3 * x3) + (y1 * y1 - y3 * y3)) / 2;
    double delta = b * c - a * d;
    point pc = point(-(d * e - b * f) / delta, -(a * f - c * e) / delta);
    return circle(pc, len(pc - p1));
}
circle get_inv(circle c) {
    double r = (1 / (len(c.c) - c.r) - 1 / (len(c.c) + c.r)) / 2;
    point p = c.c * (r / c.r);
    return circle(p, r);
}
circle get_inv(point a, point b) {
    point p1 = a * (1.0 / (len(a) * len(a)));
    point p2 = b * (1.0 / (len(b) * len(b)));
    return get_cir(p1, p2, point(0, 0));
}
point p, pa[10], pb[10];
circle c1, c2;
int get_tangents(circle A, circle B, point* a, point* b) {
    int cnt = 0;
    if (A.r < B.r) {
        swap(A, B);
        swap(a, b);
    }
    double d2 = (A.c.x - B.c.x) * (A.c.x - B.c.x) + (A.c.y - B.c.y) * (A.c.y - B.c.y);
    double rdiff = A.r - B.r;
    double rsum = A.r + B.r;

    double base = atan2(B.c.y - A.c.y, B.c.x - A.c.x);
    double ang = acos((A.r - B.r) / sqrt(d2));
    a[cnt] = A.get_point(base + ang);
    b[cnt] = B.get_point(base + ang);
    if (sign(cross(a[cnt], A.c, b[cnt])) == sign(cross(a[cnt], point(), b[cnt])) &&
        sign(cross(a[cnt], A.c, b[cnt])) == sign(cross(a[cnt], point(), b[cnt])))
    cnt++;
    a[cnt] = A.get_point(base - ang);
    b[cnt] = B.get_point(base - ang);
    if (sign(cross(a[cnt], A.c, b[cnt])) == sign(cross(a[cnt], point(), b[cnt])) &&
        sign(cross(a[cnt], A.c, b[cnt])) == sign(cross(a[cnt], point(), b[cnt])))
    cnt++;
    return cnt;
}

int main() {
    scanf("%d", &t);
    while (t--) {
        c1.read();
        c2.read();
        p.read();
        c1.c = c1.c - p;
        c2.c = c2.c - p;
        circle invc1 = get_inv(c1);
        circle invc2 = get_inv(c2);
        int flag = get_tangents(invc1, invc2, pa, pb);
        printf("%d\n", flag);
        for (int i = 0; i < flag; i++) {
            circle c = get_inv(pa[i], pb[i]);
            c.c = c.c + p;
            printf("%.9f %.9f %.9f\n", c.c.x, c.c.y, c.r);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值