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