圆的反演(hdu4773,hdu6158,hdu6097)
hdu4773:http://acm.hdu.edu.cn/showproblem.php?pid=4773
题意:给你两个相离的圆,以及一个点,求所有和这两个圆相切,并且经过该点的圆。
我们先画出满足题意的圆,然后把这三个圆反演,给定的两个圆因为不经过p点,反演后是两个圆,然后ans圆经过p点,所以反演后是一条直线,又因为和两个圆相切,所以反演出来的直线也是和两个圆相切的,所以就是两个反演圆的外公切线了(不可以是内公切先,画画图就明白了)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define eps 1e-6 4 int sgn(double x){ 5 if( fabs(x) < eps) return 0; 6 if( x < 0) return -1; 7 return 1; 8 } 9 struct Point{ 10 double x,y; 11 Point operator - (const Point& b){ 12 return (Point){ x - b.x,y-b.y}; 13 } 14 Point operator + (const Point& b){ 15 return (Point){x+b.x,y+b.y}; 16 } 17 Point operator * (const double& b){ 18 return (Point){b * x,b * y}; 19 } 20 Point Move(double a,double d){ 21 return (Point){ x + d * cos(a),y + d * sin(a)}; 22 } 23 }; 24 struct Circle{ 25 Point o; 26 double r; 27 }c[3],c0,ansc[3]; 28 int tot; 29 double cross(Point a,Point b,Point c){ 30 return (b.x - a.x) * (c.y - a.y) - (c.x - a.x)*(b.y - a.y); 31 } 32 double dot(Point a,Point b,Point c){ 33 return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y); 34 } 35 double dis(Point a,Point b){ 36 return sqrt( (a.x - b.x) * (a.x - b.x) + (a.y - b.y)*(a.y - b.y)); 37 } 38 Point Point_Inver(Circle c0,Point P){ 39 Point OP = P - c0.o; 40 double len = dis(c0.o,P); 41 len = len*len; 42 return c0.o + OP*( c0.r * c0.r / len ); 43 } 44 Circle Circle_Inver(Circle c0,Circle a){ 45 Circle res; 46 Point OA = a.o - c0.o; 47 double len = dis(a.o,c0.o); 48 Point up = c0.o + OA * ( ( len + a.r) / len ); 49 Point down = c0.o + OA *( (len - a.r) / len ); 50 up = Point_Inver(c0,up); 51 down = Point_Inver(c0,down); 52 res.o = (up+down) * 0.5; 53 res.r = dis(up,down) * 0.5; 54 return res; 55 } 56 Circle Line_Inver(Circle c0,Point a,Point b){ 57 Circle res; 58 double d = fabs( cross(a,c0.o,b) / dis(a,b)); 59 res.r = c0.r * c0.r / (2.0 * d); 60 61 double len = dot(a,b,c0.o) / dis(a,b); 62 Point AB = b - a; 63 Point c = a + AB * (len/dis(a,b)); 64 Point CO = c - c0.o; 65 res.o = c0.o + CO * (res.r/d); 66 67 //double len = dis(a,c[1].o); 68 //res.o = c0.o + (a-c[1].o) * (res.r/len); 69 return res; 70 } 71 void solve(){ 72 for(int i = 1;i<=2;++i) c[i] = Circle_Inver(c0,c[i]); 73 if( c[1].r < c[2].r - eps) swap(c[1],c[2]); 74 Point v = c[2].o - c[1].o; 75 double a1 = atan2(v.y,v.x); 76 double a2 = acos( (c[1].r - c[2].r) / dis(c[1].o,c[2].o)); 77 Point p1 = c[1].o.Move(a1 + a2,c[1].r); 78 Point p2 = c[2].o.Move(a1 + a2,c[2].r); 79 //cerr<<p1.x<<" "<<p1.y<<" "<<p2.x<<" "<<p2.y<<endl; 80 if( sgn(cross(c[1].o,p1,p2)) == sgn(cross(c0.o,p1,p2)) ) ansc[++tot] = Line_Inver(c0,p1,p2); 81 p1 = c[1].o.Move(a1-a2,c[1].r); 82 p2 = c[2].o.Move(a1-a2,c[2].r); 83 //cerr<<p1.x<<" "<<p1.y<<" "<<p2.x<<" "<<p2.y<<endl; 84 if( sgn(cross(c[1].o,p1,p2)) == sgn(cross(c0.o,p1,p2)) ) ansc[++tot] = Line_Inver(c0,p1,p2); 85 } 86 int main(){ 87 c0.r = 10.0; 88 int T; scanf("%d",&T); 89 while(T--){ 90 tot = 0; 91 for(int i = 1;i<=2;++i) scanf("%lf %lf %lf",&c[i].o.x,&c[i].o.y,&c[i].r); 92 scanf("%lf %lf",&c0.o.x,&c0.o.y); 93 solve(); 94 printf("%d\n",tot); 95 for(int i = 1;i<=tot;++i) printf("%.8f %.8f %.8f\n",ansc[i].o.x,ansc[i].o.y,ansc[i].r); 96 } 97 return 0; 98 }
hdu6158:http://acm.hdu.edu.cn/showproblem.php?pid=6158
给你这两个大圆的半径,问你往里面塞n个小圆,这n个小圆面积和是多少。
题解:很明显是以左边的切点做圆心,半径1的圆,对这两个大圆做圆的反演,然后就反演出两条平行直线了(画画图发现两条直线平行y轴),其他小圆因为和两大圆相切,所以和两直线相切,也就是夹在中间的那一堆圆,直接算就OK了。
参考博客:https://www.cnblogs.com/flipped/p/7397942.html
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define eps 1e-8 4 const double rr = 1.0; 5 const double pi = acos(-1.0); 6 double r1,r2; 7 int n; 8 double area(double x){return pi*x*x;} 9 double yan(int id){ 10 double x = rr*(r2 + r1)/r1/r2/4; 11 double r = rr/r1/2 - x; 12 double y = 2 * id * r; 13 double len = sqrt(x*x+y*y); 14 double d1 = len - r,d2 = len + r; 15 double R = rr * ( 1/d1 - 1/d2) * 0.5; 16 return area(R); 17 } 18 double solve(){ 19 double ans = 0; 20 ans += area( (r2-r1) ); 21 --n; 22 for(int i = 1;i<=(n+1)/2;++i){ 23 double tem = yan(i); 24 ans += tem; 25 if( i * 2 <= n ) ans += tem; 26 if( tem * (n-i*2) < eps ) break; 27 } 28 return ans; 29 } 30 int main(){ 31 int T; scanf("%d",&T); 32 while(T--){ 33 scanf("%lf %lf",&r1,&r2); 34 if(r1 > r2) swap(r1,r2); 35 scanf("%d",&n); 36 printf("%.5f\n",solve()); 37 } 38 return 0; 39 }
hdu6097:http://acm.hdu.edu.cn/showproblem.php?pid=6097
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define eps 1e-6 4 struct Point{ 5 double x,y; 6 }p1,q1,p2,q2,o; 7 double dis2(Point a,Point b){ 8 return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); 9 } 10 double dis(Point a,Point b){ 11 return sqrt( dis2(a,b) ); 12 } 13 double r; 14 Point change(Point a){ 15 Point res = a; 16 double len2 = dis2(a,o); 17 res.x = a.x * ( r * r /len2); 18 res.y = a.y * ( r * r /len2); 19 return res; 20 } 21 void solve(){ 22 double pd = dis(p1,o); 23 if(pd < eps){ 24 printf("%.7f\n",2 * r); 25 return; 26 } 27 p2 = change(p1); 28 q2 = change(q1); 29 Point f; 30 f.x = ( p2.x + q2.x ) /2; 31 f.y = ( p2.y + q2.y ) /2; 32 double fd = dis(f,o); 33 //cerr<<fd<<" "<<f.x<<" "<<f.y<<" "<<p2.x<<" "<<p2.y<<" "<<q2.x<<" "<<q2.y<<endl; 34 double ans; 35 if( r - fd > -eps){ 36 //cerr<<"ok1"<<endl; 37 ans = dis(q2,p2); 38 ans *= pd/r; 39 } 40 else{ 41 //cerr<<"ok2"<<endl; 42 Point D; 43 D.x = f.x * r / fd; 44 D.y = f.y * r / fd; 45 ans = 2 * dis(D,p1); 46 } 47 printf("%.7f\n",ans); 48 } 49 int main(){ 50 int T; scanf("%d",&T); 51 o.x = o.y = 0; 52 while(T--){ 53 scanf("%lf %lf %lf %lf %lf",&r,&p1.x,&p1.y,&q1.x,&q1.y); 54 solve(); 55 } 56 return 0; 57 }