HDU 4773 Problem of Apollonius——圆反演

题面

  HDU4773

解析

    大概是圆反演的模板吧。

  以点$P(x3, y3)$为反演中心,任意长为反演半径,将两个已知圆反演,设反演后的圆为$A‘$, $B‘$,所求圆反演后为一条直线,根据题目中的要求,该直线为两圆的外公切线。因此我们只需要求出两圆的外公切线即可。

  然后会发现WA了,因为题目中还有一个要求,所求圆要外切于两圆,即反演变换后反演中心$P$和$A‘$的圆心要在同侧。

  还有一个我一开始做错了的地方,原来的圆心$O$反演后就不是新的圆心了!!!可以连接$PO$,求其与圆的两个交点,两个交点的反演点中点才是新的圆心。

 代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const double eps = 1e-11, Pi = 3.14159265358979323;

int T, cnt, num;
double R;

struct node{
    double fir, sec;
    node(){}
    node(double x, double y) {
        fir = x;
        sec = y;
    }
}p, c[5], d[5];

node operator + (node x, node y)
{
    return node(x.fir + y.fir, x.sec + y.sec);
}

node operator - (node x, node y)
{
    return node(x.fir - y.fir, x.sec - y.sec);
}

node operator * (node x, double y)
{
    return node(x.fir * y, x.sec * y);
}

node operator / (node x, double y)
{
    return node(x.fir / y, x.sec / y);
}

//Rotate vector counterclockwise by alpha
node rotate(node x, double y)//rad
{
    return node(x.fir * cos(y) - x.sec * sin(y), x.fir * sin(y) + x.sec * cos(y));
}

//Cross product
double crp(node x, node y)
{
    return x.fir * y.sec - x.sec * y.fir;
}

//Dot product
double dtp(node x, node y)
{
    return x.fir * y.fir + x.sec * y.sec;
}

//Distance
double dist(node x)
{
    return sqrt(dtp(x, x));
}

//Find the intersection of two straight lines
//x, y are the vector starting points
//u, v are the direction vectors
node itpt(node x, node u, node y, node v)
{
    node t = x - y;
    double rat = crp(v, t) / crp(u, v);
    return x + u * rat;
}

struct circ{
    node o;
    double r;
}a, b, aa, bb, ans[5];

//Find the common tangent of two circles
void tagt(circ x, circ y)
{
    if(x.r < y.r)    swap(x, y);
    double len = dist(x.o - y.o);

    //External common tangent
    double alp = acos((x.r - y.r) / len);
    node tmp = y.o - x.o, t = rotate(tmp, alp);
    c[++cnt] = x.o + t / len * x.r;
    tmp = x.o - y.o; t = rotate(tmp, Pi + alp);
    d[cnt] = y.o + t / len * y.r;
    tmp = y.o - x.o; t = rotate(tmp, 2 * Pi - alp);
    c[++cnt] = x.o + t / len * x.r;
    tmp = x.o - y.o; t = rotate(tmp, Pi - alp);
    d[cnt] = y.o + t / len * y.r;

    //Internal common tangent
    /*alp = acos((x.r + y.r) / len);
    tmp = y.o - x.o; t = rotate(tmp, alp);
    c[++cnt] = x.o + t / len * x.r;
    tmp = x.o - y.o; t = rotate(tmp, alp);
    d[cnt] = y.o + t / len * y.r;
    tmp = y.o - x.o; t = rotate(tmp, 2 * Pi - alp);
    c[++cnt] = x.o + t / len * x.r;
    tmp = x.o - y.o; t = rotate(tmp, 2 * Pi - alp);
    d[cnt] = y.o + t / len * y.r;*/
}

int check(double x)
{
    return (x > eps) - (x < -eps);
}

void out(double x)
{
    printf("%.8f ", fabs(x) < 0.000000005? 0: x);
}

int main()
{
    scanf("%d", &T);
    R = 1.0;
    double len1, len2;
    node tmp, t;
    while(T --)
    {
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &a.o.fir, &a.o.sec, &a.r, &b.o.fir, &b.o.sec, &b.r, &p.fir, &p.sec);
        len1 = dist(a.o - p);
        tmp = p + (a.o - p) / len1 * (len1 - a.r);
        len2 = dist(tmp - p);
        tmp = p + (tmp - p) / len2 * (R / len2);
        t = p + (a.o - p) / len1 * (len1 + a.r);
        len2 = dist(t - p);
        t = p + (t - p) / len2 * (R / len2);
        aa.o = (tmp + t) / 2;
        aa.r = dist(aa.o - tmp);

        len1 = dist(b.o - p);
        tmp = p + (b.o - p) / len1 * (len1 - b.r);
        len2 = dist(tmp - p);
        tmp = p + (tmp - p) / len2 * (R / len2);
        t = p + (b.o - p) / len1 * (len1 + b.r);
        len2 = dist(t - p);
        t = p + (t - p) / len2 * (R / len2);
        bb.o = (tmp + t) / 2;
        bb.r = dist(bb.o - tmp);

        cnt = num = 0;
        tagt(aa, bb);
        for(int i = 1; i <= cnt; ++i)
        {
            if(fabs(crp(c[i] - p, d[i] - p)) < eps || check(crp(d[i] - c[i], p - c[i])) !=  check(crp(d[i] - c[i], aa.o - c[i])))    continue;
            ++ num;
            tmp = c[i] - d[i];
            tmp = rotate(tmp, Pi / 2);
            tmp = itpt(p, tmp, d[i], c[i] - d[i]);
            len1 = dist(tmp - p);
            tmp = p + (tmp - p) / len1 * (R / len1);
            ans[num].o = (p + tmp) / 2;
            ans[num].r = dist(ans[num].o - p);
        }
        printf("%d\n", num);
        for(int i = 1; i <= num; ++i)
        {
            out(ans[i].o.fir);
            out(ans[i].o.sec);
            printf("%.8f\n", ans[i].r);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Joker-Yza/p/12227895.html

时间: 2024-11-01 10:52:41

HDU 4773 Problem of Apollonius——圆反演的相关文章

hdu 4773 Problem of Apollonius

莫名其妙就AC了-- 圆的反演-- 神马是反演? 快去恶补奥数-- #include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<alg

hdu 4773 圆的反演

第一次接触反演算法. 通过反演圆以求得反演后的直线. 圆的相切即为直线和圆的相切,切点是关键. 值得注意的是,不过中心的直线反演后得到不过中心的圆,圆圆反演后得到另一个圆,因为中途可以得到一条直线,所以可以简化计算. 反演半径不可以随意选取,过大会导致精度问题. #include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <vector>#includ

【计算几何】【圆反演】hdu6158 The Designer

给你内外那俩圆的半径,让你按图中标号的顺序往缝里塞n个小圆,问你小圆的总面积. 不知道圆反演的先去查一下定义. 将两个圆的切点视作反演中心,任取反演半径(比如1),将两个圆反演成两条平行直线,则那些小圆都变成相同大小啦!就很好算了,我们再将小圆通过反演算回它原来的面积即可. 怎样求原小圆的面积呢? 只需求得AB的长度即可.因为A'距离原点的距离我们知道,B'距离原点的距离我们也知道,OA,OB就很好求了,作个差就是AB. (这套CCPC网络赛的题是我们学校的人出的,线下测题的时候,我的这份代码能

HDU 4910 Problem about GCD

Problem about GCD Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 470    Accepted Submission(s): 77 Problem Description Given integer m. Find multiplication of all 1<=a<=m such gcd(a, m)=1 (cop

【计算几何】【圆反演】hdu6097 Mindis

给你一个中心在原点的圆,再给你俩在圆内且到原点距离相等的点P,Q,让你在圆上求一点D,最小化DP+DQ. http://blog.csdn.net/qq_34845082/article/details/77099332 附:过反演中心的圆反演后变成一条和该圆正交的直线. 不过反演中心的圆反演后是一个与原圆关于反演中心位似的圆. 不过反演中心的直线反演后变成一个过反演中心且与其正交的圆. #include<cstdio> #include<cmath> using namespac

HDU 2256 Problem of Precision (矩阵快速幂)

HDU 2256 Problem of Precision (矩阵快速幂) ACM 题目地址:HDU 2256 Problem of Precision 题意: 给出一个式子,求值. 分析: 推起来最后那步会比较难想. 具体过程见: 表示共轭只听说过复数的和图的... 这构题痕迹好明显... 跟基友开玩笑说:如果遇到这种题,推到Xn+Yn*sqrt(6)这步时,打表最多只能打到10就爆int了,这是输出正解和Xn,说不定眼神好能发现ans = Xn * 2 - 1呢.= =... 代码: /*

hdu 4910 Problem about GCD(数论)

题目连接:hdu 4910 Problem about GCD 题目大意:给定M,判断所有小于M并且和M互质的数的积取模M的值. 解题思路:有个数论的结论,若为偶数,M=M/2. 可以写成M=pk,即只有一种质因子时,答案为M-1,否则为1.特殊情况为4的倍数,不包括4. 首先用1e6以内的素数去试除,如果都不可以为p,那么对大于1e6的情况判断一下是否为素数,是素数也可以(k=1),否则开方计算,因为M最大为1e18,不可能包含3个大于1e6的质因子. #include <cstdio> #

HDU 4910 Problem about GCD(米勒拉宾)

HDU 4910 Problem about GCD 题目链接 题意:给定一个数字,求出1 - n之间与他互质的数的乘积mod n 思路:看了网上别人找出来的规律,原文链接 然后由于这题的n很大,也没法直接判定,可以这样搞,先去试10^6以内的素数,判断可不可以,如果不行,再利用米勒拉宾判下是否是素数,如果不是的话,把这个数字开根在平方,判断是不是完全平方数,这样做的原因是数字最大10^18,如果没有10^6以内的质因子,又不是质数的话,那么他最多只能包含2个质因子了,那么如果他不是一个完全平方

hdu String Problem(最小表示法入门题)

hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <string> using namespace std; const int N = 10010; int n; char s[105]; map<