hdu6097-反演点+相似三角形

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6097


题意:

给一个圆C和圆心O,P、Q是圆上或圆内到圆心距离相等的两个点,在圆上取一点D,求|PD| + |QD|的最小值


反演点定义:https://baike.baidu.com/item/反演点/5735267?fr=aladdin


做点P、Q的反演点P'、Q', |OP| * |OP'| = r ^ 2, |OQ| * |OQ'| = r ^ 2.

|OP| / r = r / |OP'|, 即|OP| / |OD| = |OD| / |OP'|, 所以△OPD ∽ △ODP', 同理, △OQD ∽ △ODQ', 相似比为|OP| / r.

所以, |PD| + |QD| = (|P'D| + |Q'D|) * |OP| / r. 转化为求|P'D| + |Q'D|的最小值

若P'Q'与圆C有交点,则|P'D| + |Q'D|的最小值为|P'Q'| (此时D为P'Q'与圆C的交点, |P'D| + |Q'D| 为直线,值最小)

若P'Q'与圆C无交点,则D为PQ的中垂线与圆C的交点时, |P'D| + |Q'D|取得最小值(以P、Q为焦点做椭圆,令椭圆不断变大,椭圆与圆C有一个交点时,此交点即为点D)


代码:

# include <iostream>
# include <algorithm>
# include <cstdio>
# include <cstring>
# include <cmath>
# include <cstdlib>
using namespace std;
typedef long long ll;
const double eps = 1e-7;
double xp, yp, xq, yq;
double r;

int main(void)
{
    int T; scanf("%d", &T);
    while (T-- && scanf("%lf", &r)) {
        scanf("%lf %lf %lf %lf", &xp, &yp, &xq, &yq);
        double op = sqrt(xp * xp + yp * yp);
        if (fabs(op) < eps) { printf("%.7lf\n", 2 * r); continue; }
        double l = r * r / op;
        double xp2 = xp * l / op, yp2 = yp * l / op;
        double xq2 = xq * l / op, yq2 = yq * l / op;
        double xm = (xp2 + xq2) / 2, ym = (yp2 + yq2) / 2;
        if (xm * xm + ym * ym <= r * r) {
            double ans = sqrt((xq2 - xp2) * (xq2 - xp2) + (yq2 - yp2) * (yq2 - yp2)) * op / r;
            printf("%.7f\n", ans);
        } else {
            double d = sqrt(xm * xm + ym * ym);
            double t = r / d;
            double x = xm * t, y = ym * t;
            double ans = 2 * sqrt((x - xp) * (x - xp) + (y - yp) * (y - yp));
            printf("%.7f\n", ans);
        }
    }

    return 0;
}

/*
5
4
4 0
0 4
4
0 3
3 0
4
0 2
2 0
4
0 1
1 0
4
0 0
0 0
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值