zoukankan      html  css  js  c++  java
  • HDU4773 Problem of Apollonius(反演变换)

    HDU4773 Problem of Apollonius(反演变换)

    题意:

    给定两个相离的圆,一个点P,求出过点P并且和两个圆都外切的所有圆。

    思路:

    以P为反演中心将两个圆O1,O2分别反演,得到O1',O2',则和O1,O2相切的圆反演后是一条不经过P点且与O1'、O2‘相切的直线。显然这条直线就是O1'、O2’的公切线。因为要求和O1、O2外切的圆,因此反演后的直线必定使O1'、O2'、P在圆的同一侧。筛选出符合条件的公切线再反演回去就是所求的圆了。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const double eps = 1e-8;
    const double PI=acos(-1.0);
    int sgn(double x) {
        if(fabs(x) < eps)
            return 0;
        if(x < 0)
            return -1;
        return 1;
    }
    struct Point {
        double x,y;
        Point() {}
        Point(double _x,double _y) {
            x = _x;
            y = _y;
        }
        Point operator -(const Point &b)const {
            return Point(x - b.x,y - b.y);
        }
        Point operator +(const Point &b)const {
            return Point(x + b.x,y +b.y);
        }
        double operator ^(const Point &b)const {
            return x*b.y - y*b.x;
        }
        double operator *(const Point &b)const {
            return x*b.x + y*b.y;
        }
        Point operator *(double b)const {
            return Point(x*b,y*b);
        }
        Point Rotate(double rad){ //逆时针旋转
            return Point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));
        }
        double len(){//Vector
            return sqrt(x*x+y*y);
        }
        void stdd(){//Vector
            double le=len();
            x/=le;
            y/=le;
        }
        void input(){
            scanf("%lf%lf",&x,&y);
        }
        void output(){
            printf("(%.8f,%.8f) ",x,y);
        }
    };
    struct Circle {
        Point o;
        double r;
        Circle(){}
        void input(){
            o.input();
            scanf("%lf",&r);
        }
        void output(){
            printf("%.8f %.8f %.8f
    ",o.x,o.y,r);
        }
    };
    double xmult(Point p0,Point p1,Point p2) { //p0p1 X p0p2
        return (p1-p0)^(p2-p0);
    }
    double dist(Point a,Point b) {
        return sqrt( (b - a)*(b - a) );
    }
    double getArea(Point a,Point b,Point c){//三角形面积S
        return fabs(xmult(a,b,c))/2.0;
    }
    double distLP(Point a,Point b,Point p){//p到ab的距离
        return getArea(a,b,p)*2/dist(a,b);
    }
    Circle CtC(Circle C,Point p,double r){//圆到圆的反演
        Circle res;
        double t = dist(C.o,p);
        double x = r*r / (t - C.r);
        double y = r*r / (t + C.r);
        res.r = (x - y) / 2.0;
        double s = (x + y) / 2.0;
        res.o = p + (C.o - p) * (s / t);
        return res;
    }
    Circle LtC(Point a,Point b,Point p,double r){//直线到圆的反演
        double d=distLP(a,b,p);
        d=r*r/d;
        Circle c;
        c.r=d/2;
        Point v1;
        if(xmult(a,b,p)>0)
            v1=(a-b).Rotate(PI/2);
        else
            v1=(b-a).Rotate(PI/2);
        v1.stdd();
        c.o=p+v1*c.r;
        return c;
    }
    Circle c[10];
    Point p;
    bool check(Point a,Point b,Point p){
        if(sgn(xmult(a,b,p))==sgn(xmult(a,b,c[0].o))&&sgn(xmult(a,b,p))==sgn(xmult(a,b,c[1].o)))
            return 1;
        else return 0;
    }
    vector<Circle>ans;
    void solve(){
        ans.clear();
        double r=1;
        c[0]=CtC(c[0],p,r);
        c[1]=CtC(c[1],p,r);
        if(c[0].r>c[1].r)swap(c[0],c[1]);
        Point v1=c[0].o-c[1].o;
        double d=dist(c[0].o,c[1].o);
        Point a,b;
        double alpha=acos((c[1].r-c[0].r)/d);
        v1.stdd();
        a=c[1].o+v1.Rotate(-alpha)*c[1].r;
        b=c[0].o+v1.Rotate(-alpha)*c[0].r;
        if(check(a,b,p))ans.push_back(LtC(a,b,p,r));
        a=c[1].o+v1.Rotate(alpha)*c[1].r;
        b=c[0].o+v1.Rotate(alpha)*c[0].r;
        if(check(a,b,p))ans.push_back(LtC(a,b,p,r));
    }
    int main () {
        int T;
        scanf("%d",&T);
        while(T--){
            c[0].input();c[1].input();
            scanf("%lf%lf",&p.x,&p.y);
            solve();
            printf("%d
    ",ans.size());
            for(int i=0;i<ans.size();i++){
                ans[i].output();
            }
        }
    }
    
  • 相关阅读:
    数据窗口的缓冲区
    RowsMove()
    update
    defparameter defconstant
    1+ 1
    原则
    incf decf
    eql equal
    上司找谈话
    判断回文的函数palindrome?
  • 原文地址:https://www.cnblogs.com/ucprer/p/14110069.html
Copyright © 2011-2022 走看看