题意:给出两个相离的圆O1,O2和圆外一点P,求构造这样的圆:同时与两个圆相外切,且经过点P,输出圆的圆心和半径

分析:画图很容易看出这样的圆要么存在一个,要么存在两个:此题直接解方程是不容易的,先看看反演的定义:已知一圆C,圆心为O,半径为r,如果P与P’在过圆心O的直线上,且,则称P与P'关于O互为反演。

反演的性质:

首先设出反演圆心O和反演半径R

1、圆外一点P与圆内一点P‘会一一对应的反演OP*OP'=R*R

2、经过O的圆,反演后成为不经过O的一条直线

3、不经过O的圆,反演后成为另一个圆,且圆心并不对应

4、不经过O的直线反演后成为一个经过O的圆

5、过O的直线反演后不变

具体参考该http://blog.csdn.net/acdreamers/article/details/16966369

注意:反演中心圆的半径要设大一点,否则会有精度问题

代码:
  1. #include"stdio.h"
  2. #include"string.h"
  3. #include"stdlib.h"
  4. #include"queue"
  5. #include"algorithm"
  6. #include"string.h"
  7. #include"string"
  8. #include"math.h"
  9. #include"vector"
  10. #include"stack"
  11. #include"map"
  12. #define eps 1e-4
  13. #define inf 0x3f3f3f3f
  14. #define M 609
  15. #define PI acos(-1.0)
  16. using namespace std;
  17. struct node//二维点坐标
  18. {
  19. double x,y;
  20. node(){};
  21. node(double xx,double yy)
  22. {
  23. x=xx;
  24. y=yy;
  25. }
  26. node operator+(node b)
  27. {
  28. return node(x+b.x,y+b.y);
  29. }
  30. node operator-(node b)
  31. {
  32. return node(x-b.x,y-b.y);
  33. }
  34. node operator*(double b)
  35. {
  36. return node(x*b,y*b);
  37. }
  38. double operator*(node b)
  39. {
  40. return x*b.x+y*b.y;
  41. }
  42. double operator^(node b)
  43. {
  44. return x*b.y-y*b.x;
  45. }
  46. };
  47. struct Circle//定义圆心和半径
  48. {
  49. node center;
  50. double r;
  51. }p[M];
  52. struct Line//定义直线一般式的三个参数ABC
  53. {
  54. double A,B,C;
  55. };
  56. struct Line2//定义两条直线
  57. {
  58. Line s,e;
  59. };
  60. double len(node a)//求向量的长度
  61. {
  62. return sqrt(a*a);
  63. }
  64. double dis(node a,node b)//求两个点的距离
  65. {
  66. return len(a-b);
  67. }
  68. double cross(node a,node b,node c)//求叉乘
  69. {
  70. return (b-a)^(c-a);
  71. }
  72. double dot(node a,node b,node c)//求点乘
  73. {
  74. return (b-a)*(c-a);
  75. }
  76. Circle InverCircle(node p,double R,Circle c)//已知反演中心和反演半径,求圆c的反形圆
  77. {
  78. Circle ret;
  79. double pc=dis(p,c.center);
  80. ret.r=R*R/2*(1/(pc-c.r)-1/(pc+c.r));
  81. double pret=R*R/(pc+c.r)+ret.r;
  82. ret.center.x=p.x+(pret/pc)*(c.center.x-p.x);
  83. ret.center.y=p.y+(pret/pc)*(c.center.y-p.y);
  84. return ret;
  85. }
  86. node InterPoint(node p,Line L)//过直线外一点与直线L的垂足
  87. {
  88. node ret;
  89. ret.y=(L.A*L.A*p.y-L.A*L.B*p.x-L.B*L.C)/(L.A*L.A+L.B*L.B);
  90. ret.x=(L.B*L.B*p.x-L.A*L.B*p.y-L.A*L.C)/(L.A*L.A+L.B*L.B);
  91. return ret;
  92. }
  93. Circle InverLine(node p,double R,Line L)//已知不过反演中心的直线,求其反形圆(反形圆过反演中心)
  94. {
  95. Circle ret;
  96. node q=InterPoint(p,L);
  97. double l1=dis(p,q);
  98. double l2=R*R/l1;
  99. ret.r=l2/2;
  100. ret.center.x=p.x+ret.r/l1*(q.x-p.x);//利用相似三角形求解
  101. ret.center.y=p.y+ret.r/l1*(q.y-p.y);
  102. return ret;
  103. }
  104. Line line(node a,node b)//已知两个不同的点,求过这两个点的直线
  105. {
  106. Line l;
  107. l.A=b.y-a.y;
  108. l.B=a.x-b.x;
  109. l.C=b.x*a.y-a.x*b.y;
  110. return l;
  111. }
  112. double disLL(Line L1,Line L2)//两条平行线间垂直距离
  113. {
  114. return fabs(L1.C-L2.C)/sqrt(L1.A*L1.A+L1.B*L1.B);
  115. }
  116. double disPL(node p,Line L)//求点到直线的距离
  117. {
  118. return fabs(L.A*p.x+L.B*p.y+L.C)/sqrt(L.A*L.A+L.B*L.B);
  119. }
  120. node Ratate(node a,double rad)//向量逆时针旋转rad的角度
  121. {
  122. return node(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
  123. }
  124. Line PointCutCircle(node p,Circle c,int clock)//过圆外一点p且与圆的切线,clock代表两个不同的切线
  125. {
  126. Line ret;
  127. node she;
  128. she=c.center-p;
  129. double pc=dis(c.center,p);
  130. double rad=asin(c.r/pc);
  131. if(clock==-1)//逆时针旋转
  132. {
  133. node she1=Ratate(she,rad);
  134. ret.A=she1.y;
  135. ret.B=-she1.x;
  136. ret.C=she1.x*p.y-p.x*she1.y;
  137. }
  138. if(clock==1)//顺时针旋转
  139. {
  140. node she1=Ratate(she,-rad);
  141. ret.A=she1.y;
  142. ret.B=-she1.x;
  143. ret.C=she1.x*p.y-p.x*she1.y;
  144. }
  145. return ret;
  146. }
  147. Line2 CircleCutCircle(Circle O1,Circle O2)//求两个相离的圆的两条外公切线
  148. {
  149. Line2 L;
  150. Line l1,l2,L1;
  151. if(fabs(O1.r-O2.r)<eps)//当量圆半径相同时
  152. {
  153. L1=line(O1.center,O2.center);
  154. l1.A=L1.A;
  155. l1.B=L1.B;
  156. l1.C=L1.C+fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
  157. l2.A=L1.A;
  158. l2.B=L1.B;
  159. l2.C=L1.C-fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
  160. L.s=l1;
  161. L.e=l2;
  162. }
  163. else//当两个圆的半径不同时
  164. {
  165. if(O1.r>O2.r)
  166. swap(O1,O2);
  167. Circle O;
  168. O.center=O2.center;
  169. O.r=O2.r-O1.r;
  170. L1=PointCutCircle(O1.center,O,-1);
  171. l1.A=L1.A;
  172. l1.B=L1.B;
  173. l1.C=L1.C+fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
  174. l2.A=L1.A;
  175. l2.B=L1.B;
  176. l2.C=L1.C-fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
  177. if(fabs(disPL(O1.center,l1)-O1.r)<eps&&fabs(disPL(O2.center,l1)-O2.r)<eps)
  178. L.s=l1;
  179. if(fabs(disPL(O1.center,l2)-O1.r)<eps&&fabs(disPL(O2.center,l2)-O2.r)<eps)
  180. L.s=l2;
  181. L1=PointCutCircle(O1.center,O,1);
  182. l1.A=L1.A;
  183. l1.B=L1.B;
  184. l1.C=L1.C+fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
  185. l2.A=L1.A;
  186. l2.B=L1.B;
  187. l2.C=L1.C-fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
  188. if(fabs(disPL(O1.center,l1)-O1.r)<eps&&fabs(disPL(O2.center,l1)-O2.r)<eps)
  189. L.e=l1;
  190. if(fabs(disPL(O1.center,l2)-O1.r)<eps&&fabs(disPL(O2.center,l2)-O2.r)<eps)
  191. L.e=l2;
  192. }
  193. return L;
  194. }
  195. int main()
  196. {
  197. int T,cnt;
  198. scanf("%d",&T);
  199. while(T--)
  200. {
  201. Circle C1,C2,C3,C4,C,ans[4];
  202. Line2 L;
  203. node P;
  204. scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&C1.center.x,&C1.center.y,&C1.r,&C2.center.x,&C2.center.y,&C2.r,&P.x,&P.y);
  205. C3=InverCircle(P,30.0,C1);
  206. C4=InverCircle(P,30.0,C2);
  207. L=CircleCutCircle(C3,C4);
  208.  
  209. cnt=0;
  210. C=InverLine(P,30.0,L.s);
  211. if(fabs(dis(C.center,C1.center)-C1.r-C.r)<eps&&fabs(dis(C.center,C2.center)-C2.r-C.r)<eps)
  212. ans[cnt++]=C;
  213.  
  214. C=InverLine(P,30.0,L.e);
  215. if(fabs(dis(C.center,C1.center)-C1.r-C.r)<eps&&fabs(dis(C.center,C2.center)-C2.r-C.r)<eps)
  216. ans[cnt++]=C;
  217.  
  218. printf("%d\n",cnt);
  219. for(int i=0;i<cnt;i++)
  220. printf("%.8lf %.8lf %.8lf\n",ans[i].center.x,ans[i].center.y,ans[i].r);
  221. }
  222. }

圆的反演变换(HDU4773)的更多相关文章

  1. HOJ 13102 Super Shuttle (圆的反演变换)

    HOJ 13102 Super Shuttle 链接:http://49.123.82.55/online/?action=problem&type=show&id=13102 题意: ...

  2. 【 HDU4773 】Problem of Apollonius (圆的反演)

    BUPT2017 wintertraining(15) #5G HDU - 4773 - 2013 Asia Hangzhou Regional Contest problem D 题意 给定两个相离 ...

  3. Pick定理、欧拉公式和圆的反演

    Pick定理.欧拉公式和圆的反演 Tags:高级算法 Pick定理 内容 定点都是整点的多边形,内部整点数为\(innod\),边界整点数\(ednod\),\(S=innod+\frac{ednod ...

  4. HDU-4773 Problem of Apollonius (圆的反演)

    参考: https://oi-wiki.org/geometry/inverse/ https://blog.csdn.net/acdreamers/article/details/16966369 ...

  5. 「HDU6158」 The Designer(圆的反演)

    题目链接多校8-1009 HDU - 6158 The Designer 题意 T(<=1200)组,如图在半径R1.R2相内切的圆的差集位置依次绘制1,2,3,到n号圆,求面积之和(n< ...

  6. The Designer (笛卡尔定理+韦达定理 || 圆的反演)

    Nowadays, little haha got a problem from his teacher.His teacher wants to design a big logo for the ...

  7. CF77E Martian Food(圆的反演or 笛卡尔定理+韦达定理)

    题面 传送门 这题有两种方法(然而两种我都想不到) 方法一 前置芝士 笛卡尔定理 我们定义一个圆的曲率为\(k=\pm {1\over r}\),其中\(r\)是圆的半径 若在平面上有两两相切,且六个 ...

  8. 2017多校第6场 HDU 6097 Mindis 计算几何,圆的反演

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6097 题意:有一个圆心在原点的圆,给定圆的半径,给定P.Q两点坐标(PO=QO,P.Q不在圆外),取圆 ...

  9. hdu6158(圆的反演)

    hdu6158 题意 初始有两个圆,按照标号去放圆,问放完 \(n\) 个圆后的总面积. 分析 圆的反演的应用. 参考blog 设反演圆心为 \(O\) 和反演半径 \(R\) 圆的反演的定义: 已知 ...

随机推荐

  1. Java中的匿名对象

    匿名对象就是没有明确给出名字的对象.一般匿名对象只使用一次,而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用. 一个普通的常量字符串就可以表示一个匿名String对象. 比如可以 int len ...

  2. Flink - FLIP

    https://cwiki.apache.org/confluence/display/FLINK/Flink+Improvement+Proposals FLIP-1 : Fine Grained ...

  3. PureBasic 集成Form设计器的使用

    The PureBasic IDE has a very powerful integrated form designer, which allows to design easily window ...

  4. 【转】如何使php的MD5与C#的MD5一致?

    有c#生成MD5的代码如下: class CreateMD5 { static void Main(string[] args) { string source = "提问指南"; ...

  5. App Previews操作经验

    App Previews操作经验 http://www.cocoachina.com/ios/20140924/9741.html http://www.cocoachina.com/bbs/read ...

  6. CRUD操作 create创建 read读取 update修改 delete删除

    1.注释语法:--,#2.后缀是.sql的文件是数据库查询文件3.保存查询4.在数据库里面 列有个名字叫字段 行有个名字叫记录 CRUD操作:create 创建(添加)read 读取update 修改 ...

  7. pro10

    1.本次课学习到的知识点: 什么是数组?为什么要使用数组?如何定义数组? 如何引用数组元素? 2. 实验过程中遇到的问题及解决方法: 在最后一个试验中,在输出最大小标那里进行了仔细的思考,刚开始思考应 ...

  8. 低功耗蓝牙4.0BLE编程-nrf51822开发(1)

    为了省钱,也为了提高手动能力,只买了块核心板,仿真器用的是旧的jinkv7,自己搭扩展板,DIY就这样开始了. 买这块之前做了些调查,最终选定了nrf51822,功耗低,性能强,开发难度小,虽然比TI ...

  9. Ajax如何实现跨域问题

    一个域名的组成 http:// www . abc.com : 8080 /scripts/jquery.js 协议 子域名 主域名 端口号 请求资源地址 当协议.子域名.主域名.端口号中任意一个不同 ...

  10. [LeetCode] Substring with Concatenation of All Words(good)

    You are given a string, S, and a list of words, L, that are all of the same length. Find all startin ...