zoukankan      html  css  js  c++  java
  • HDU 4773 (圆的反演)

    题目:传送门

    题目

    题意:给定两个圆的半径和圆心,它们是相离的,在这两个圆外给定一个点p,输出所有过点p且与已知的两个

    圆外切的圆。

    思路

    根据圆的反演的一些性质,可以将过点 p 的圆与已知两个圆外切转化为过点 p 的直线,与已知两个圆外切。

    圆的反演的一些性质:

    1、过反演中心的圆,反形(经过反演之后的图形)为不过反演中心的直线。

    2、不过反演中心的直线,反形为过反演中心的圆。

    3、不过反演中心的圆,反形也为不过反演中心的圆,并且反演中心为这两个互为反形的圆的位似中心。

    4、相切两圆的反象仍相切,若切点恰是反演中心,则其反象为两平行线。

    5、相离的两圆反演(反演中心不在圆上)后仍然相离;两圆相切,若反演中心在某圆上,则为反形为相切的直线与圆。

    我们以 p 为反演中心,半径自设,然后对已知的两个圆反演,然后求两圆的外切线,将外切线反演为圆即为所求。

    圆的反演:参考

    #include <bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define UI unsigned int
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f3f
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    #define lb(x) ((x) & (-(x)))
    #define dbg(x) cout<<#x<<" = "<<x<<endl;
    using namespace std;
    
    const int N = 1e6 + 5;
    const double 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 operator / (const double a) { return Point(a/x, a/y); }
        void Input() { scanf("%lf %lf", &x, &y); }
        void Output() { printf("%.8f %.8f
    ", 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("%.8f %.8f %.8f
    ", o.x, o.y, r); }
    };
    
    double dis(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) - (c.x-a.x)*(b.y-a.y); }
    double Cross(Point a, Point b) { return a.x*b.y - a.y*b.x; }
    double Dot(Point a, Point b, Point c) { return (b.x-a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y); }
    int dcmp(double x) { return (x > eps) - (x < -eps); }
    
    Point Point_Inver(Circle c0,Point P){
        Point OP = P - c0.o;
        double len = dis(c0.o,P);
        len = len*len;
        return c0.o + OP*( c0.r * c0.r / len );
    }
    Circle Circle_Inver(Circle c0,Circle a){
        Circle res;
        Point OA = a.o - c0.o;
        double len = dis(a.o,c0.o);
        Point up = c0.o + OA * ( ( len + a.r) / len );
        Point down = c0.o + OA *( (len - a.r) / len );
        up = Point_Inver(c0,up);
        down = Point_Inver(c0,down);
        res.o = (up+down) * 0.5;
        res.r = dis(up,down) * 0.5;
        return res;
    }
    Circle Line_Inver(Circle c0,Point a,Point b){
        Circle res = Circle();
        double d = fabs(Cross(a,c0.o,b) / dis(a,b));
        res.r = c0.r * c0.r / (2.0 * d);
        double len = Dot(a,b,c0.o) / dis(a,b);
        Point AB = b - a;
        Point c = a + AB * (len/dis(a,b));
        Point CO = c - c0.o;
        res.o = c0.o + CO * (res.r/d);
        //double len = dis(a,c[1].o);
        //res.o = c0.o + (a-c[1].o) * (res.r/len);
        return res;
    }
    
    Circle c[20];
    Circle c0;
    int tot = 0;
    
    void solve() {
    
        c[0].Input(); c[1].Input();
        c0.o.Input();
        c0.r = 5.00;
    
        Point p = c0.o;
    
        c[0] = Circle_Inver(c0, c[0]);
        c[1] = Circle_Inver(c0, c[1]);
    
        if(c[1].r > c[0].r) swap(c[0], c[1]);
    
        Point v = c[1].o - c[0].o;
    
        double alpha = atan2(v.y, v.x);
        double d = dis(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(dcmp(Cross(a, c[0].o, b)) == dcmp(Cross(a, p, b)) &&
           dcmp(Cross(a, c[1].o, b)) == dcmp(Cross(a, p, b)))
            c[++k] = Line_Inver(c0, a, b);
    
        a = c[0].getPoint(alpha - beta);
        b = c[1].getPoint(alpha - beta);
    
        if(dcmp(Cross(a, c[0].o, b)) == dcmp(Cross(a, p, b)) &&
           dcmp(Cross(a, c[1].o, b)) == dcmp(Cross(a, p, b)))
            c[++k] = Line_Inver(c0, a, b);
    
        printf("%d
    ", k - 2);
    
        rep(i, 3, k) c[i].Output();
    
    }
    
    
    int main() {
    
        int _; scanf("%d", &_);
        while(_--) solve();
    
    //    solve();
    
        return 0;
    }
  • 相关阅读:
    git, tornado 小计
    算法小计-列表排列
    CMDB小计1
    linux 中mysql的主从复制
    SQL语句的种类
    mysql的结构,段页区,及客户端命令
    mysql的程序结构,实例, 及mysql的多实例
    在linux中操作mysql误删root用户的应对方法
    MySQL面试
    linux下载安装mysal
  • 原文地址:https://www.cnblogs.com/Willems/p/13825848.html
Copyright © 2011-2022 走看看