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

 

 

 

 

posted on 2013-06-18 17:08  Ac_coral  阅读(280)  评论(0编辑  收藏  举报

导航