关闭

圆的反演变换

14845人阅读 评论(3) 收藏 举报
分类:

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4773


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

外切的所有圆的总数和它们的圆心坐标和半径。



分析:根据题意,我们设已知两个圆的半径分别为,它们的圆心分别为,设点p的坐标为


并设要求的圆的圆心为,半径为,那么根据它们的关系我们可以很快就列出方程组:




然后,现在的问题就是来解,但是你会发现这个方程是很难解的,因此为了简化问题,我们利用反演变换来做。



那么,怎么用反演变换来做? 首先,得知道什么是反演变换以及它有什么性质。


反演的定义:


已知一圆C,圆心为O,半径为r,如果P与P’在过圆心O的直线上,且,则称P与P'关于O互为反演。


反演的性质:


(1)除反演中心外,平面上的每一个点都只有唯一的反演点,且这种关系是对称的,位于反演圆上的点,保持在原处,位于

反演圆外部的点,变为圆内部的点,位于反演圆内部的点,变为圆外部的点。 举个最简单的例子,区间以1为反演

半径,那么反演后的区间就是,这就是一维反演,而圆的反演是二维反演。


(2)任意一条不过反演中心的直线,它的反形是经过反演中心的圆,反之亦然,特别地,过反演中心相交的圆,变为不过反

演中心的相交直线。





定理:不过反演中心的圆,它的反形是一个圆,反演中心是这两个互为反形的圆的一个位似中心,任意一对反演点是逆对应

点。用图形来解释,如下图:




那么,对于一个不过反演中心的圆,怎样求它的反形圆?


很容易知道我们只需要求出反形圆的圆心和半径就可以了。


对于上图我们设圆C1的半径为,C2的半径为,反演半径为


那么根据反演的定义有:




那么,消去得到:




这样我们就得到了反形圆的半径,那么还要求反形圆的圆心。



由于C1和O两点的坐标已知,而且我们知道O,C1,C2位于同一直线上,那么很明显对于C2的坐标,我们可以这样计算:


设O的坐标为,C1的坐标为,C2的坐标为


那么有:




至于由上面解处可以很容易得到,这样我们就完成了圆的反演变换。



由于本题的做法是这样的,先以点P为为反演中心,反演半径随便设置都可以,为了计算方便就设为1,把圆C1和圆C2反演后再求这两个圆的

公切线,再把这个公切线反演回去,那么就是一个过点P的圆,且与原来的C1和C2相切。



那么接下来就是如何计算两个圆的公切线了。这里只需要考虑公切线在同一侧的情况。那么,这个自己画图就能很容易计算了。

找到公切线后还要把它反演成圆,这个圆还经过P点,那么很容易得到了。


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>

using namespace std;
double const eps = 1e-8;

struct Point
{
    double x,y;
    Point(double a = 1.0,double b = 1.0):x(a),y(b){}
    Point operator + (const Point &a)
    {
        return Point(x+a.x,y+a.y);
    }
    Point operator - (const Point &a)
    {
        return Point(x-a.x,y-a.y);
    }
    Point operator * (const double a)
    {
        return Point(a*x,a*y);
    }
    Point Trans()
    {
        return Point(-y,x);
    }
    void Input()
    {
        scanf("%lf%lf",&x,&y);
    }
} ;

struct Circle
{
    Point o;
    double r;
    Circle(Point a = Point(),double b = 1.0):o(a),r(b) {}
    Point getPoint(double alpha)
    {
        return o + Point(r*cos(alpha),r*sin(alpha));
    }
    void Input()
    {
        o.Input();
        scanf("%lf",&r);
    }
    void Output()
    {
        printf("%.8lf %.8lf %.8lf\n",o.x,o.y,r);
    }
} ;

Point p;
Circle c[15];

double dist(Point A,Point B)
{
    return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
}

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);
}

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

Circle Inverse(Circle C)
{
    Circle T;
    double t = dist(C.o,p);
    double x = 1.0 / (t - C.r);
    double y = 1.0 / (t + C.r);
    T.r = (x - y) / 2.0;
    double s = (x + y) / 2.0;
    T.o = p + (C.o - p) * (s / t);
    return T;
}

void add(Point a,Point b,int &k)
{
    double t = cross(a,p,b);
    if(t < 0) t = -t;
    double d = dist(a,b);
    t /= d;
    if(t > eps)
    {
        double w = 0.5 / t;
        Point dir = (b-a).Trans();
        Point a1 = p + dir * (w / d);
        Point b1 = p - dir * (w / d);
        if(fabs(cross(a,b,a1)) < fabs(cross(a,b,b1)))
           c[k++] = Circle(a1,w);
        else
           c[k++] = Circle(b1,w);
    }
}

int Work()
{
    c[0] = Inverse(c[0]);
    c[1] = Inverse(c[1]);
    if(c[1].r > c[0].r) swap(c[1],c[0]);
    Point v = c[1].o - c[0].o;
    double alpha = atan2(v.y,v.x);
    double d = dist(c[0].o,c[1].o);
    double beta  = acos((c[0].r - c[1].r) / d);
    int k = 2;
    Point a = c[0].getPoint(alpha + beta);
    Point b = c[1].getPoint(alpha + beta);
    if(sign(cross(a,c[0].o,b)) == sign(cross(a,p,b)) &&
       sign(cross(a,c[1].o,b)) == sign(cross(a,p,b)))
        add(a,b,k);
    a = c[0].getPoint(alpha - beta);
    b = c[1].getPoint(alpha - beta);
    if(sign(cross(a,c[0].o,b)) == sign(cross(a,p,b)) &&
       sign(cross(a,c[1].o,b)) == sign(cross(a,p,b)))
        add(a,b,k);
    return k - 2;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        c[0].Input();
        c[1].Input();
        p.Input();
        int num = Work();
        printf("%d\n",num);
        for(int i=0;i<num;i++)
            c[i+2].Output();
    }
    return 0;
}



4
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

【圆的反演变换】hdu4773

这个blog解释的挺不错:http://blog.csdn.net/acdreamers/article/details/16966369 给定不相交的两个圆以及圆外一点,找一个经过给定点的圆与其他...
  • huyuncong
  • huyuncong
  • 2014-03-09 21:46
  • 1695

怎样才能将刘徽割圆术动画演示

所谓“割圆术”,是用圆内接正多边形的周长去无限逼近圆周并以此求取圆周率的方法。它是由我国古代的伟大数学家刘徽,提出来的。他在数学上的重大贡献是将我国最古的数学著作之一《九章算术》详细整理(公元263年...
  • Xshell_Xmanager
  • Xshell_Xmanager
  • 2017-04-14 11:04
  • 1617

图像处理之霍夫变换圆检测算法

演示应用Hough变换检测图像中得圆,得到检测目标,详解讲述了这一算法过程 并且展示了算法运行的效果. 讨论了hough变换检测的先决条件.
  • jia20003
  • jia20003
  • 2013-12-10 23:07
  • 31528

圆的反演变换(HDU4773)

传递闭包 在一个有向(无向)连通图中,如果节点i与k联通,k与j联通,则i和j联通,传递闭包就是把所有传递性的节点求出来,之后就知道了任意两个节点的连通性,只需枚举节点的联通情况即可,无需考虑最短路...
  • u012859437
  • u012859437
  • 2014-11-05 16:38
  • 658

【圆的反演变换+cdq分治】共点圆

http://www.tsinsen.com/ViewGProblem.page?gpid=A1381
  • huyuncong
  • huyuncong
  • 2014-07-04 15:56
  • 876

反介入/区域拒止:现代战争的演变

在战争史上,对手总会尝试拒止另一方在战场上的行动自由。过去的反介入方式兼有保护己方力量和防止敌军获取优势的目的。作为远征部队,美军正依赖于安全地向战区部署,以及获取和维持制空、制天、制海权的能力。但是...
  • wmdcstdio
  • wmdcstdio
  • 2016-01-18 13:35
  • 5672

详解:大型网站架构演变和知识体系

  • 2014-12-11 12:45
  • 180KB
  • 下载

详解:大型网站架构演变和知识体系

  • 2011-04-17 08:27
  • 37KB
  • 下载

复杂系统的结构演变

  • 2008-06-21 15:42
  • 162KB
  • 下载

淘宝消息中间件技术演变.pdf

  • 2015-03-05 15:18
  • 1.31MB
  • 下载
    个人资料
    • 访问:2471461次
    • 积分:24483
    • 等级:
    • 排名:第304名
    • 原创:472篇
    • 转载:42篇
    • 译文:0篇
    • 评论:506条
    最新评论