题意:

给出两个圆的圆心坐标和半径,求这两个圆的公切线切点的坐标及对应线段长度。若两圆重合,有无数条公切线则输出-1.

输出是按照一定顺序输出的。

分析:

首先情况比较多,要一一判断,不要漏掉。

如果高中的那点老底还在的话,代码还是很好理解的。

 

  1 //#define LOCAL
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 using namespace std;
  8 
  9 const double PI = acos(-1.0);
 10 const double EPS = 1e-8;
 11 struct Point
 12 {
 13     double x, y;
 14     Point(double x=0, double y=0):x(x), y(y) {}
 15 
 16 };
 17 typedef Point Vector;
 18 Vector operator + (Vector A, Vector B)
 19 {
 20     return Vector(A.x+B.x, A.y+B.y);
 21 }
 22 Vector operator - (Vector A, Vector B)
 23 {
 24     return Vector(A.x-B.x, A.y-B.y);
 25 }
 26 Vector operator * (Vector A, double p)
 27 {
 28     return Vector(A.x*p, A.y*p);
 29 }
 30 Vector operator / (Vector A, double p)
 31 {
 32     return Vector(A.x/p, A.y/p);
 33 }
 34 double dcmp(double x)
 35 {
 36     if(fabs(x) < EPS)    return 0;
 37     else return x < 0 ? -1 : 1;
 38 }
 39 bool operator < (const Vector& a, const Vector& b)
 40 {
 41     return dcmp(a.x-b.x) < 0 || dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) < 0;
 42 }
 43 bool operator == (const Vector& a, const Vector& b)
 44 {
 45     return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
 46 }
 47 double Dot(Vector a, Vector b)
 48 {
 49     return a.x*b.x + a.y*b.y;
 50 }
 51 double Cross(Vector a, Vector b)
 52 {
 53     return a.x*b.y - a.y*b.x;
 54 }
 55 double Length(Vector a)
 56 {
 57     return sqrt(Dot(a, a));
 58 }
 59 struct Circle
 60 {
 61     double x, y, r;
 62     Circle(double x, double y, double r):x(x), y(y), r(r) {}
 63     Point point(double a)
 64     {
 65         return Point(x + r*cos(a), y + r*sin(a));
 66     }
 67 };
 68 int getTangents(Circle A, Circle B, Point* a, Point* b)
 69 {
 70     int cnt = 0;
 71     if(A.r < B.r)    { swap(A, B); swap(a, b); }
 72     double d2 = (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y);
 73     double rdiff = A.r - B.r;
 74     double rsum = A.r + B.r;
 75     if(d2 < rdiff*rdiff)    return 0;    //内含
 76 
 77     double base = atan2(B.y-A.y, B.x-A.x);
 78     if(dcmp(d2) == 0 && dcmp(A.r - B.r) == 0)    return -1; //重合
 79     if(dcmp(d2 - rdiff*rdiff) == 0)    //内切
 80     {
 81         a[cnt] = A.point(base); b[cnt] = B.point(base); cnt++;
 82         return 1;
 83     }
 84 
 85     //有外公切线
 86     double ang = acos((A.r - B.r) / sqrt(d2));
 87     a[cnt] = A.point(base + ang); b[cnt] = B.point(base + ang); cnt++;
 88     a[cnt] = A.point(base - ang); b[cnt] = B.point(base - ang); cnt++;
 89     if(dcmp(rsum*rsum - d2) == 0)
 90     {//外切
 91         a[cnt] = b[cnt] = A.point(base); cnt++;
 92     }
 93     else if(dcmp(d2 - rsum*rsum) > 0)
 94     {
 95         ang = acos((A.r + B.r) / sqrt(d2));
 96         a[cnt] = A.point(base + ang); b[cnt] = B.point(PI + base + ang); cnt++;
 97         a[cnt] = A.point(base - ang); b[cnt] = B.point(PI + base - ang); cnt++;
 98     }
 99     return cnt;
100 }
101 
102 int main(void)
103 {
104     #ifdef    LOCAL
105         freopen("10674in.txt", "r", stdin);
106     #endif
107     
108     int x1, y1, r1, x2, y2, r2;
109     while(scanf("%d%d%d%d%d%d", &x1, &y1, &r1, &x2, &y2, &r2) == 6 && r1 && r2)
110     {
111         Point a[4], b[4];
112         Circle C1(x1, y1, r1), C2(x2, y2, r2);
113         int n = getTangents(C1, C2, a, b);
114         printf("%d\n", n);
115         int p[4] = {0, 1, 2, 3};
116         for(int i = 0; i < n; ++i)
117             for(int j = i+1; j < n; ++j)
118                 if(a[p[j]] < a[p[i]] || (a[p[j]] == a[p[i]] && b[p[j]] < b[p[i]]))    swap(p[i], p[j]);
119         for(int i = 0; i < n; ++i)
120             printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n", a[p[i]].x, a[p[i]].y, b[p[i]].x, b[p[i]].y, Length(a[p[i]] - b[p[i]]));
121     }
122 
123     return 0;
124 }
代码君

相关文章:

  • 2022-12-23
  • 2022-01-05
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-07-12
  • 2022-12-23
  • 2021-04-11
  • 2022-12-23
  • 2021-07-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案