• UVa12304


    这篇总结可能很长 - - 需要一点点的分析。


    首先,这题最大的收获:

    关于eps的宏定义,并不一定总是一个固定值,1e-10之类。。这个浮点常量也不一定是越小越好。。

    对于这个题来讲,const double eps = 1E-6;  const double eps = 1E-5;   const double eps = 1E-4;       甚至 const double eps = 1E-1;       都可以AC。

    再小一点就不行了~


     接着,说一下这个:

    struct Line {
      Point p;
      Vector v;
      Line(Point p, Vector v):p(p),v(v) { }
      Point point(double t) {
        return p + v*t;
      }
      Line move(double d) {
        return Line(p + Normal(v)*d, v);
      }
    };

     Line可以用一点p和这条直线的方向向量v来唯一确定;

    其中,move()函数的功能是,对直线进行平移d个单位,函数返回值也是直线;

    具体来讲,对于直线L1,L1是由点p和方向向量v确定,向量v的法线向量为Normal(v),

    那么通过点p且与L1垂直直线方程可以表示为:p+Normal(v)*t,当t=d时,就是p1点的坐标p+Normal(v)*d。

    此时,L2的就可以用点p1和方向向量v来表示了


     接下来程序的六个主要模块:

    给定三角形三个顶点坐标,求三角形外接圆的圆心坐标与半径

    /******************* Problem 1 **********************/
    
    Circle CircumscribedCircle(Point p1, Point p2, Point p3) {
      double Bx = p2.x-p1.x, By = p2.y-p1.y;
      double Cx = p3.x-p1.x, Cy = p3.y-p1.y;
      double D = 2*(Bx*Cy-By*Cx);
      double cx = (Cy*(Bx*Bx+By*By) - By*(Cx*Cx+Cy*Cy))/D + p1.x;
      double cy = (Bx*(Cx*Cx+Cy*Cy) - Cx*(Bx*Bx+By*By))/D + p1.y;
      Point p = Point(cx, cy);
      return Circle(p, Length(p1-p));
    }

    这个是真没推出来,推出来的是这个:

    记三角形的定点为(Ax, Ay), (Bx, By), (Cx, Cy),
    外接圆的圆心为(Rx,Ry), 

    由于圆心到3个定点的距离相等. 因此有:
        (Ax-Rx)^2 + (Ay-Ry)^2  = (Bx-Rx)^2 + (By-Ry)^2 (1)
        (Ax-Rx)^2 + (Ay-Ry)^2  = (Cx-Rx)^2 + (Cy-Ry)^2 (2) 
    由(1)式得:Ax^2 + Ay^2 - 2*Ax*Rx - 2*Ay*Ry = Bx^2 + By^2 - 2*Bx*Rx - 2*By*Ry (3)
    由(2)式得:Ax^2 + Ay^2 - 2*Ax*Rx - 2*Ay*Ry = Cx^2 + Cy^2 - 2*Cx*Rx - 2*Cy*Ry  (4)
    由(3)式得:Rx = (Ax^2 + Ay^2 - Bx^2 - By^2 + 2*(By-Ay) * y)/(2*(Ax-Bx))
    代入(4)得:
       Rx = 此处省略30字
       Ry = 此处省略30字
    总之是个简单的2元一次方程.


    给定三角形三个顶点坐标,求三角形内切圆的圆心坐标与半径

    /******************* Problem 2 **********************/
    
    Circle InscribedCircle(Point p1, Point p2, Point p3) {
      double a = Length(p2-p3);
      double b = Length(p3-p1);
      double c = Length(p1-p2);
      Point p = (p1*a+p2*b+p3*c)/(a+b+c);
      return Circle(p, DistanceToLine(p, p1, p2));
    }

     这个是公式,推导过程:

    三角形ABC的内切圆圆心为 三个角平分线交点  到三边距离相等

    既然知道坐标  便可知三边所在直线方程  设该圆心坐标为(x,y)  用点到直线距离公式

    ⊿ABC中,A(x1,y1),B(x2,y2),C(x3,y3),那么⊿ABC内心I的坐标是:
      (a·x1/(a+b+c)+b·x2(a+b+c)+c·x3(a+b+c),a·y1/(a+b+c)+b·y2/(a+b+c)+c·y3(a+b+c)). 

    其中:a b c是角A角B角C对应的边


    给定圆心坐标和半径,求过定点p并且和这个圆相切的所有切线

    /******************* Problem 3 **********************/
    
    // 过点p到圆C的切线。v[i]是第i条切线的向量。返回切线条数
    int getTangents(Point p, Circle C, Vector* v) {
      Vector u = C.c - p;
      double dist = Length(u);
      if(dist < C.r) return 0;
      else if(dcmp(dist - C.r) == 0) { // p在圆上,只有一条切线
        v[0] = Rotate(u, PI/2);
        return 1;
      } else {
        double ang = asin(C.r / dist);
        v[0] = Rotate(u, -ang);
        v[1] = Rotate(u, +ang);
        return 2;
      }
    }

    求出所有过定点p并且和直线相切的半径为r的圆

    /******************* Problem 4 **********************/
    
    vector<Point> CircleThroughPointTangentToLineGivenRadius(Point p, Line L, double r) {
      vector<Point> ans;
      double t1, t2;
      getLineCircleIntersection(L.move(-r), Circle(p, r), t1, t2, ans);
      getLineCircleIntersection(L.move(r), Circle(p, r), t1, t2, ans);
      return ans;
    }

     


    给两条不平行的直线,求所有半径为r并且同时和这两条直线相切的圆

    /******************* Problem 5 **********************/
    
    vector<Point> CircleTangentToLinesGivenRadius(Line a, Line b, double r) {
      vector<Point> ans;
      Line L1 = a.move(-r), L2 = a.move(r);
      Line L3 = b.move(-r), L4 = b.move(r);
      ans.push_back(GetLineIntersection(L1, L3));
      ans.push_back(GetLineIntersection(L1, L4));
      ans.push_back(GetLineIntersection(L2, L3));
      ans.push_back(GetLineIntersection(L2, L4));
      return ans;
    }       

     

    给定两个相离的圆,求出所有和这两个圆外切的,半径为r的圆

    /******************* Problem 6 **********************/
    
    vector<Point> CircleTangentToTwoDisjointCirclesWithRadius(Circle c1, Circle c2, double r) {               
      vector<Point> ans;
      /*
      Vector v = c2.c - c1.c;
      double dist = Length(v);
      int d = dcmp(dist - c1.r -c2.r - r*2);
      if(d > 0) return ans;
      */
      getCircleCircleIntersection(Circle(c1.c, c1.r+r), Circle(c2.c, c2.r+r), ans);
      return ans;
    }

     

  • 相关阅读:
    VS无法打开类视图
    C#中的Boolean类型
    Some websites to learn Ubuntun
    HOW TO : Install Eclipse with C/C++ in Ubuntu 12.04
    [转载]Android开发之旅:环境搭建及HelloWorld
    C#学习笔记—了解C#
    C#继承机制
    使用U盘安装Ubuntu
    [Z]ubuntu12.04搭建android开发环境
    Windows程序的调用方法
  • 原文地址:https://www.cnblogs.com/Accoral/p/3142665.html
Copyright © 2020-2023  润新知