UVa 10674 (求两圆公切线) Tangents

题意:

给出两个圆的圆心坐标和半径,求这两个圆的公切线切点的坐标及对应线段长度。若两圆重合,有无数条公切线则输出-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 }
代码君

 

写的第一份,样例过,自己随机生成的1000组数据和lrj的代码对比,输出也是一模一样的,可就是无线WA。

这里还是贴一下这份“神奇”的代码吧,也许日后能发现这个隐藏的错误。

  1 //#define LOCAL

  2 #include <cstdio>

  3 #include <cstring>

  4 #include <algorithm>

  5 #include <vector>

  6 #include <cmath>

  7 using namespace std;

  8 

  9 struct Point

 10 {

 11     double x, y;

 12     Point(double x=0, double y=0) :x(x),y(y) {}

 13 };

 14 typedef Point Vector;

 15 const double EPS = 1e-8;

 16 Vector operator + (Vector A, Vector B)    { return Vector(A.x + B.x, A.y + B.y); }

 17 Vector operator - (Vector A, Vector B)    { return Vector(A.x - B.x, A.y - B.y); }

 18 Vector operator * (Vector A, double p)    { return Vector(A.x*p, A.y*p); }

 19 Vector operator / (Vector A, double p)    { return Vector(A.x/p, A.y/p); }

 20 bool operator < (const Point& a, const Point& b)

 21 { return a.x < b.x || (a.x == b.x && a.y < b.y); }

 22 int dcmp(double x)

 23 { if(fabs(x) < EPS) return 0; else return x < 0 ? -1 : 1; }

 24 bool operator == (const Point& a, const Point& b)

 25 { return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0; }

 26 double Dot(Vector A, Vector B)

 27 { return A.x*B.x + A.y*B.y; }

 28 double Length(Vector A)    { return sqrt(Dot(A, A)); }

 29 

 30 struct Circle

 31 {

 32     Point c;    //Ô²ÐÄ

 33     double r;    //°ë¾¶

 34     //Circle(Point c, double r):c(c), r(r)    {}

 35     Point point(double a)

 36     {//Çó¶ÔÓ¦Ô²ÐĽǵĵã

 37         return Point(c.x + r*cos(a), c.y + r*sin(a));

 38     }

 39 };

 40 double angle(Vector v)    { return atan2(v.y, v.x); }

 41 const double PI = acos(-1.0); 

 42 

 43 int getTangents(Circle A, Circle B, Point* a, Point* b)

 44 {

 45     int cnt = 0;

 46     if(A.r < B.r)    { swap(A, B); swap(a, b); }

 47     double d2 = (A.c.x-B.c.x)*(A.c.x-B.c.x) + (A.c.y-B.c.y)*(A.c.y-B.c.y);

 48     double rdiff = A.r - B.r;

 49     double rsum  = A.r + B.r;

 50     if(d2 < rdiff*rdiff)    return 0;    //ÄÚº¬

 51 

 52     double base = atan2(B.c.y-A.c.y, B.c.x-A.c.x);

 53     if(dcmp(d2) == 0 && dcmp(A.r-B.r) == 0)    return -1;    //Á½Ô²Öغϣ¬ÎÞÇî¶àÌõÇÐÏß

 54     if(dcmp(d2 - rdiff*rdiff) == 0)                //ÄÚÇÐ

 55     {

 56         a[cnt] = A.point(base);

 57         b[cnt] = B.point(base);

 58         cnt++;

 59         return 1;

 60     }

 61     //ÓÐÍ⹫ÇÐÏß

 62     double ang = acos((A.r-B.r) / sqrt(d2));

 63     a[cnt] = A.point(base+ang); b[cnt] = B.point(base+ang); cnt++;

 64     a[cnt] = A.point(base-ang); b[cnt] = B.point(base-ang); cnt++;

 65     

 66     if(dcmp(d2 - rsum*rsum) == 0)    //Ò»ÌõÄÚ¹«ÇÐÏß

 67     {

 68         a[cnt] = b[cnt] = A.point(base); cnt++;

 69     }

 70     else if(dcmp(d2 - rsum*rsum) > 0)

 71     {

 72         double ang = acos((A.r+B.r) / sqrt(d2));

 73         a[cnt] = A.point(base+ang); b[cnt] = B.point(base+ang+PI); cnt++;

 74         a[cnt] = A.point(base-ang); b[cnt] = B.point(base-ang+PI); cnt++;

 75     }

 76     //for(int i = 0; i < cnt; ++i)

 77       //    printf("%.5lf %.5lf %.5lf %.5lf\n", a[i].x, a[i].y, b[i].x, b[i].y);

 78     return cnt;

 79 }

 80 

 81 int main(void)

 82 {

 83     #ifdef    LOCAL

 84         freopen("10674in.txt", "r", stdin);

 85         //freopen("10674out.txt", "w", stdout);

 86     #endif

 87 

 88     int x1, y1, r1, x2, y2, r2;

 89     while(scanf("%d%d%d%d%d%d", &x1, &y1, &r1, &x2, &y2, &r2) == 6 && dcmp(r1) > 0)

 90     {

 91         Point a[10], b[10];

 92         /*Point p1(x1, y1), p2(x2, y2);

 93         Circle C1(p1, r1), C2(p2, r2);*/

 94         Circle C1, C2;

 95         C1.c.x=x1, C1.c.y=y1, C1.r=r1;

 96         C2.c.x=x2, C2.c.y=y2, C2.r=r2;

 97         int n = getTangents(C1, C2, a, b);

 98         printf("%d\n", n);

 99         if(n > 0)

100         {

101             int p[4] = {0, 1, 2, 3};

102             for(int i = 0; i < n; ++i)

103                 for(int j = i+1; j < n; ++j)

104                     if(a[p[j]] < a[p[i]] || (a[p[j]] == a[p[i]] && b[p[j]] < b[p[i]]))    swap(p[i], p[j]);

105             for(int i = 0; i < n; ++i)

106                 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]]));

107         }

108     }

109 

110     return 0;

111 }
WA掉的代码君

 

你可能感兴趣的:(uva)