题链:
https://vjudge.net/problem/UVA-10674
题解:
计算几何,求两个圆的公切线。
《算法竞赛入门经典——训练指南》P266,讲得很清楚的。
大致是分为6种情况——内含,重合,内切,相交,外切,相离这六个情况去处理,
找到共通点,便于代码编写。
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const double eps=1e-8; const double Pi=acos(-1); int sign(double x){ if(fabs(x)<=eps) return 0; return x<0?-1:1; } struct Point{ double x,y; Point(double _x=0,double _y=0):x(_x),y(_y){} void Read(){scanf("%lf%lf",&x,&y);} }; struct Circle{ Point o; double r; Point GP(double a){//Get_Point return Point(o.x+r*cos(a),o.y+r*sin(a)); } }C1,C2; struct Intersect{ Point P[2]; bool operator <(const Intersect &rtm) const{ return sign(P[0].x-rtm.P[0].x)<0||(sign(P[0].x-rtm.P[0].x)==0&&sign(P[0].y-rtm.P[0].y)<0); } }ANS[7]; typedef Point Vector; Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);} Vector operator - (Point A,Point B){return Vector(A.x-B.x,A.y-B.y);} Vector operator * (Point A,double p){return Vector(A.x*p,A.y*p);} double operator ^ (Vector A,Vector B){return A.x*B.y-A.y*B.x;} double operator * (Vector A,Vector B){return A.x*B.x+A.y*B.y;} double GPA(Vector A){//Get_Polar_Angle return atan2(A.y,A.x); } double GL(Vector A){//Get_Length return sqrt(A*A); } int GCCI(Circle A,Circle B){//Get_Circle_Circle_Intersection int cnt=0,a=0,b=1; if(A.r<B.r) swap(A,B),swap(a,b); Vector u=B.o-A.o; double d=GL(u),rdec=A.r-B.r,radd=A.r+B.r; if(sign(d-rdec)<0) return 0; //内含 if(sign(d)==0&&A.r==B.r) return -1; //重合,无线多 double base=GPA(u); if(sign(d-rdec)==0){ //内切 ANS[++cnt].P[a]=A.GP(base); ANS[cnt].P[b]=B.GP(base); return cnt; } double da=acos((A.r-B.r)/d); //2条外公切线 ANS[++cnt].P[a]=A.GP(base+da); ANS[cnt].P[b]=B.GP(base+da); ANS[++cnt].P[a]=A.GP(base-da); ANS[cnt].P[b]=B.GP(base-da); if(sign(d-radd)==0){ //1条内公切线 ANS[++cnt].P[a]=A.GP(base); ANS[cnt].P[b]=B.GP(base+Pi); } else if(sign(d-radd)>0){ //2条内公切线 da=acos((A.r+B.r)/d); ANS[++cnt].P[a]=A.GP(base+da); ANS[cnt].P[b]=B.GP(base+da+Pi); ANS[++cnt].P[a]=A.GP(base-da); ANS[cnt].P[b]=B.GP(base-da+Pi); } return cnt; } int main(){ int cnt; while(1){ C1.o.Read(); scanf("%lf",&C1.r); C2.o.Read(); scanf("%lf",&C2.r); if(!C1.o.x&&!C1.o.y&&!C1.r&&!C2.o.x&&!C2.o.y&&!C2.r) break; cnt=GCCI(C1,C2); printf("%d\n",cnt); if(cnt<=0) continue; sort(ANS+1,ANS+cnt+1); for(int i=1;i<=cnt;i++){ printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n",ANS[i].P[0].x,ANS[i].P[0].y,ANS[i].P[1].x,ANS[i].P[1].y,GL(ANS[i].P[1]-ANS[i].P[0])); } } return 0; }