ZOJ 1450 Minimal Circle 点集的最小圆覆盖

From: http://blog.csdn.net/zmx354/article/details/17076267

 

给定一个点集,求出能覆盖点集内所有点的半径最小的圆。包含点在圆上的情况。个人感觉算是比较麻烦的计算几何模板了。

在网上看了很多解题,大多数都摘抄自《求一个包含点集所有点的最小圆的算法》这篇论文。

论文中提出的算法一共分一下四步:

第 1 步. 在点集中任取 3 点 A , B , C .

第 2 步. 作一个包 含 A , B , C 三点的最小 圆. 圆周可 能通过这 3 点( 如图 1 所示) , 也 可能只通过
其中两点, 但包含第 3 点. 后一种情况圆周上的两点一定是 位于圆的一条直径的两端.

第 3 步. 在点集中找 出距离第 2 步所建圆圆心最远的点 D . 若 D 点已在圆内或圆周上, 则该
圆即为所求的圆, 算法结束. 否则, 执行第 4 步.

第 4 步. 在 A , B , C , D 中 选 3 个点, 使 由它们生成的一个 包含这 4 点的圆为最 小. 这 3 点成
为新的 A , B 和 C , 返回执 行第 2 步 .

若在第 4 步生成的圆的圆周只通过 A , B , C , D 中的两点, 则圆周上的两点取成新的 A 和 B ,
从另两点中任取一点作为新的 C .


但是我读的时候感觉其中最关键的第四步说的最为模糊了。

下面是我自己的一些关于求四边形即四个点的最小圆覆盖的一些想法。

1. 若此四边形中存在大于等于180度的内角时,则可看作求三角形的最小覆盖圆(钝角三角形为以长边做直径的圆,否则为该三角形外接圆)。

2. 若存在两个锐角,两个非锐角,则必为两个锐角顶点连线为直径的圆。

3. 若有三个锐角,一个非锐角,则必为三个锐角顶点组成的三角形的外接圆。

4. 若有四个直角,则任选其中三点组成三角形求其外接圆即可。

解决了第四步,剩下的就是按照上述算法求解了。


下面是AC代码,里面还有一些其他的模板,一直想攒一套完整的模板,所以就没删,求最小点集覆盖圆的函数为 Cal_Min_Circle(P *p,int n)。

[html] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #include <iostream>  
  2. #include <cstring>  
  3. #include <cstdlib>  
  4. #include <cstdio>  
  5. #include <queue>  
  6. #include <cmath>  
  7. #include <algorithm>  
  8.   
  9. #define LL long long  
  10. #define PI (acos(-1.0))  
  11. #define EPS (1e-10)  
  12.   
  13. using namespace std;  
  14.   
  15. struct P  
  16. {  
  17.     double x,y,a;  
  18. }p[1100],cp[1100];  
  19.   
  20. struct L  
  21. {  
  22.     P p1,p2;  
  23. } line[50];  
  24.   
  25. double X_Mul(P a1,P a2,P b1,P b2)  
  26. {  
  27.     P v1 = {a2.x-a1.x,a2.y-a1.y},v2 = {b2.x-b1.x,b2.y-b1.y};  
  28.     return v1.x*v2.y - v1.y*v2.x;  
  29. }  
  30.   
  31. double Cal_Point_Dis(P p1,P p2)  
  32. {  
  33.     return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));  
  34. }  
  35.   
  36. double Cal_Point_Dis_Pow_2(P p1,P p2)  
  37. {  
  38.     return (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y);  
  39. }  
  40.   
  41. P Cal_Segment_Cross_Point(P a1,P a2,P b1,P b2)  
  42. {  
  43.     double t = X_Mul(b1,b2,b1,a1) / X_Mul(a1,a2,b1,b2);  
  44.     P cp = {a1.x+(a2.x-a1.x)*t,a1.y+(a2.y-a1.y)*t};  
  45.     return cp;  
  46. }  
  47.   
  48. //规范相交  
  49. bool Is_Seg_Cross_Without_Point(P a1,P a2,P b1,P b2)  
  50. {  
  51.     double xm1 = X_Mul(a1,a2,a1,b1);  
  52.     double xm2 = X_Mul(a1,a2,a1,b2);  
  53.     double xm3 = X_Mul(b1,b2,b1,a1);  
  54.     double xm4 = X_Mul(b1,b2,b1,a2);  
  55.   
  56.     return (xm1*xm2 < (-EPS) && xm3*xm4 < (-EPS));  
  57. }  
  58.   
  59. //向量ab与X轴正方向的夹角  
  60. double Cal_Angle(P t,P p)  
  61. {  
  62.     return ((t.x-p.x)*(t.x-p.x) + 1 - (t.x-p.x-1)*(t.x-p.x-1))/(2*sqrt((t.x-p.x)*(t.x-p.x) + (t.y-p.y)*(t.y-p.y)));  
  63. }  
  64.   
  65. //计算 ∠b2.a.b1 的大小  
  66. double Cal_Angle_Three_Point(P a,P b1,P b2)  
  67. {  
  68.     double l1 = Cal_Point_Dis_Pow_2(b1,a);  
  69.     double l2 = Cal_Point_Dis_Pow_2(b2,a);  
  70.     double l3 = Cal_Point_Dis_Pow_2(b1,b2);  
  71.   
  72.     return acos( (l1+l2-l3)/(2*sqrt(l1*l2)) );  
  73. }  
  74.   
  75. bool cmp_angle(P p1,P p2)  
  76. {  
  77.     return (p1.a < p2.a || (fabs(p1.a-p2.a) < EPS && p1.y < p2.y) ||(fabs(p1.a-p2.a) < EPS && fabs(p1.y-p2.y) < EPS && p1.x < p2.x)   );  
  78. }  
  79.   
  80. //p为点集  应该保证至少有三点不共线  
  81. //n 为点集大小  
  82. //返回值为凸包上点集上的大小  
  83. //凸包上的点存储在cp中  
  84. int Creat_Convex_Hull(P *p,int n)  
  85. {  
  86.     int i,top;  
  87.     P re; //re 为建立极角排序时的参考点  下左点  
  88.   
  89.     for(re = p[0],i = 1; i < n; ++i)  
  90.     {  
  91.         if(re.y > p[i].y || (fabs(re.y-p[i].y) < EPS && re.x > p[i].x))  
  92.             re = p[i];  
  93.     }  
  94.   
  95.     for(i = 0; i < n; ++i)  
  96.     {  
  97.         if(p[i].x == re.x && p[i].y == re.y)  
  98.         {  
  99.             p[i].a = -2;  
  100.         }  
  101.         else p[i].a = Cal_Angle(re,p[i]);  
  102.     }  
  103.   
  104.     sort(p,p+n,cmp_angle);  
  105.   
  106.     top =0 ;  
  107.     cp[top++] = p[0];  
  108.     cp[top++] = p[1];  
  109.   
  110.     for(i = 2 ; i < n;)  
  111.     {  
  112.         if(top < 2 || X_Mul(cp[top-2],cp[top-1],cp[top-2],p[i]) > EPS)  
  113.         {  
  114.             cp[top++] = p[i++];  
  115.         }  
  116.                     else  
  117.         {  
  118.             --top;  
  119.         }  
  120.     }  
  121.   
  122.     return top;  
  123. }  
  124.   
  125. bool Is_Seg_Parallel(P a1,P a2,P b1,P b2)  
  126. {  
  127.     double xm1 = X_Mul(a1,a2,a1,b1);  
  128.     double xm2 = X_Mul(a1,a2,a1,b2);  
  129.   
  130.     return (fabs(xm1) < EPS && fabs(xm2) < EPS);  
  131. }  
  132.   
  133. bool Point_In_Seg(P m,P a1,P a2)  
  134. {  
  135.     double l1 = Cal_Point_Dis(m,a1);  
  136.     double l2 = Cal_Point_Dis(m,a2);  
  137.     double l3 = Cal_Point_Dis(a1,a2);  
  138.   
  139.     return (fabs(l1+l2-l3) < EPS);  
  140. }  
  141.   
  142. //计算三角形外接圆圆心  
  143. P Cal_Triangle_Circumcircle_Center(P a,P b,P c)  
  144. {  
  145.   
  146.     P mp1 = {(b.x+a.x)/2,(b.y+a.y)/2},mp2 = {(b.x+c.x)/2,(b.y+c.y)/2};  
  147.     P v1 = {a.y-b.y,b.x-a.x},v2 = {c.y-b.y,b.x-c.x};  
  148.   
  149.     P p1 = {mp1.x+v1.x,mp1.y+v1.y},p2 = {mp2.x+v2.x,mp2.y+v2.y};  
  150.   
  151.     return Cal_Segment_Cross_Point(mp1,p1,mp2,p2);  
  152. }  
  153.   
  154. bool Is_Acute_Triangle(P p1,P p2,P p3)  
  155. {  
  156.     //三点共线  
  157.     if(fabs(X_Mul(p1,p2,p1,p3)) < EPS)  
  158.     {  
  159.         return false;  
  160.     }  
  161.   
  162.     double a = Cal_Angle_Three_Point(p1,p2,p3);  
  163.     if(a > PI || fabs(a-PI) < EPS)  
  164.     {  
  165.         return false;  
  166.     }  
  167.     a = Cal_Angle_Three_Point(p2,p1,p3);  
  168.     if(a > PI || fabs(a-PI) < EPS)  
  169.     {  
  170.         return false;  
  171.     }  
  172.     a = Cal_Angle_Three_Point(p3,p1,p2);  
  173.     if(a > PI || fabs(a-PI) < EPS)  
  174.     {  
  175.         return false;  
  176.     }  
  177.     return true;  
  178. }  
  179.   
  180. bool Is_In_Circle(P center,double rad,P p)  
  181. {  
  182.     double dis = Cal_Point_Dis(center,p);  
  183.     return (dis < rad || fabs(dis-rad) < EPS);  
  184. }  
  185.   
  186. P Cal_Seg_Mid_Point(P p2,P p1)  
  187. {  
  188.     P mp = {(p2.x+p1.x)/2,(p1.y+p2.y)/2};  
  189.     return mp;  
  190. }  
  191.   
  192. void Cal_Min_Circle(P *p,int n)  
  193. {  
  194.     if(n == 0)  
  195.         return ;  
  196.     if(n == 1)  
  197.     {  
  198.         printf("%.2lf %.2lf %.2lf\n",p[0].x,p[0].y,0.00);  
  199.         return ;  
  200.     }  
  201.     if(n == 2)  
  202.     {  
  203.         printf("%.2lf %.2lf %.2lf\n",(p[1].x+p[0].x)/2,(p[0].y+p[1].y)/2,Cal_Point_Dis(p[0],p[1])/2);  
  204.         return ;  
  205.     }  
  206.   
  207.     P center = Cal_Seg_Mid_Point(p[0],p[1]),tc1;  
  208.   
  209.     double dis,temp,rad = Cal_Point_Dis(p[0],center),tra1;  
  210.     int i,site,a = 0,b = 1,c = 2,d,s1,s2,tp;  
  211.   
  212.     for(dis = -1,site = 0,i = 0; i < n; ++i)  
  213.     {  
  214.         temp = Cal_Point_Dis(center,p[i]);  
  215.         if(temp > dis)  
  216.         {  
  217.             dis = temp;  
  218.             site = i;  
  219.         }  
  220.     }  
  221.   
  222.     while( Is_In_Circle(center,rad,p[site]) == false )  
  223.     {  
  224.         d = site;  
  225.        // printf("a = %d b = %d c = %d d = %d\n",a,b,c,d);  
  226.   
  227.         //printf("x = %.2lf  y = %.2lf\n",center.x,center.y);  
  228.   
  229.        // printf("rad = %.2lf\n\n",rad);  
  230.        // getchar();  
  231.   
  232.         double l1 = Cal_Point_Dis(p[a],p[d]);  
  233.         double l2 = Cal_Point_Dis(p[b],p[d]);  
  234.         double l3 = Cal_Point_Dis(p[c],p[d]);  
  235.   
  236.         if((l1 > l2 || fabs(l1-l2) < EPS) && (l1 > l3 || fabs(l1-l3) < EPS))  
  237.         {  
  238.             s1 = a,s2 = d,tp = b;  
  239.         }  
  240.         else if((l2 > l1 || fabs(l1-l2) < EPS) && (l2 > l3 || fabs(l2-l3) < EPS))  
  241.         {  
  242.             s1 = b,s2 = d,tp = c;  
  243.         }  
  244.         else  
  245.         {  
  246.             s1 = c,s2 = d,tp = a;  
  247.         }  
  248.   
  249.         center = Cal_Seg_Mid_Point(p[s1],p[s2]);  
  250.         rad = Cal_Point_Dis(center,p[s1]);  
  251.   
  252.         if( Is_In_Circle(center,rad,p[a]) == false || Is_In_Circle(center,rad,p[b]) == false || Is_In_Circle(center,rad,p[c]) == false )  
  253.         {  
  254.             center = Cal_Triangle_Circumcircle_Center(p[a],p[c],p[d]);  
  255.             rad = Cal_Point_Dis(p[d],center);  
  256.             s1 = a,s2 = c,tp = d;  
  257.   
  258.             if(Is_In_Circle(center,rad,p[b]) == false)  
  259.             {  
  260.                 center = Cal_Triangle_Circumcircle_Center(p[a],p[b],p[d]);  
  261.                 rad = Cal_Point_Dis(p[d],center);  
  262.                 s1 = a,s2 = b,tp = d;  
  263.             }  
  264.             else  
  265.             {  
  266.                 tc1 = Cal_Triangle_Circumcircle_Center(p[a],p[b],p[d]);  
  267.                 tra1 = Cal_Point_Dis(p[d],tc1);  
  268.   
  269.                 if(tra1 < rad && Is_In_Circle(tc1,tra1,p[c]))  
  270.                 {  
  271.                     rad = tra1,center = tc1;  
  272.                     s1 = a,s2 = b,tp = d;  
  273.                 }  
  274.             }  
  275.   
  276.             if(Is_In_Circle(center,rad,p[c]) == false)  
  277.             {  
  278.                 center = Cal_Triangle_Circumcircle_Center(p[c],p[b],p[d]);  
  279.                 rad = Cal_Point_Dis(center,p[d]);  
  280.                 s1 = c,s2 = b,tp = d;  
  281.             }  
  282.             else  
  283.             {  
  284.                 tc1 = Cal_Triangle_Circumcircle_Center(p[c],p[b],p[d]);  
  285.                 tra1 = Cal_Point_Dis(p[d],tc1);  
  286.                 if(tra1 < rad && Is_In_Circle(tc1,tra1,p[a]))  
  287.                 {  
  288.                     rad = tra1,center = tc1;  
  289.                     s1 = b,s2 = c,tp = d;  
  290.                 }  
  291.             }  
  292.         }  
  293.   
  294.         a = s1,b = s2,c = tp;  
  295.   
  296.         for(dis = -1,site = 0,i = 0;i < n; ++i)  
  297.         {  
  298.             temp = Cal_Point_Dis(center,p[i]);  
  299.             if(temp > dis)  
  300.             {  
  301.                 dis = temp;  
  302.                 site = i;  
  303.             }  
  304.         }  
  305.     }  
  306.     printf("%.2f %.2f %.2f\n",center.x,center.y,rad);  
  307. }  
  308.   
  309. int main()  
  310. {  
  311.     int i,n;  
  312.     while(scanf("%d",&n) && n)  
  313.     {  
  314.         for(i = 0;i < n; ++i)  
  315.         {  
  316.             scanf("%lf %lf",&p[i].x,&p[i].y);  
  317.         }  
  318.         Cal_Min_Circle(p,n);  
  319.     }  

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

命令行选项解析函数(C语言):getopt()和getopt_long()

上午在看源码项目 webbench 时&#xff0c;刚开始就被一个似乎挺陌生函数 getopt_long() 给卡住了&#xff0c;说实话这函数没怎么见过&#xff0c;自然不知道这哥们是干什么的。于是乎百度了一番&#xff0c;原来是处理命令行选项参数的&#xff0c;的确&#xff0c;正规点的大…

夺命雷公狗ThinkPHP项目之----企业网站2之数据库的快速设计

我们在一个项目的时候&#xff0c;花费最多事件的估计还是数据库的时间了&#xff0c;我们的数据库暂时就这样设计好了&#xff1a; 暂时我们的数据库就这样设计好了用下先,建好后如下所示&#xff1a; 转载于:https://www.cnblogs.com/leigood/p/5411017.html

6月份美国域名总量新增近5.4万个 环比减少51%

中国IDC评述网07月03日报道&#xff1a;据域名统计机构WebHosting.info公布的数据显示&#xff0c;截至2012年6月25日&#xff0c;美国域名总量达到了79,632,920个&#xff0c;域名增幅较小。下面&#xff0c;IDC评述网与大家一起关注6月份美国域名注册量最新情况。 &#xff0…

vue+element-ui大文件的分片上传和断点续传js-spark-md5和browser-md5-file

注意&#xff1a;以下共两份代码片段&#xff0c;第一份为原博主链接代码&#xff0c;第二份自己写的整体代码&#xff08;比较乱&#xff09; 1.参考 https://www.cnblogs.com/kelelipeng/p/10158599.html &#xff08;js-spark-md5和browser-md5-file&#xff09; 和 https:…

Fedora 20 安装试用体验全程讲解

From: http://www.jb51.net/os/Fedora/177583.html Fedora 20在两次跳票后正式发布&#xff0c;主要特性包括&#xff1a;远程桌面方案X2Go&#xff1b;网络管理器支持扩大绑定和桥接功能&#xff1b;改进3D打印机支持等&#xff0c;本文中&#xff0c;作者对Fedora 20 进行安装…

NUC972配置为支持NFS

为了使用NFS进行调试。需要安装NFS server,具体的流程在上一篇博文中有较为详细的介绍。在配置内核时需要做如下的操作&#xff1a; 对于Boot option中的处理&#xff0c;可以不用写在env.txt配置也是可以的。 baudrate115200 bootargsnoinitrd consolettyS0,115200 r…

【Fedora20】 samba配置

From: http://blog.163.com/shi_shun/blog/static/23707849201452641312640/ 1、安装前的准备 关闭防火墙 //不关的后果是windows看不到本机 systemctl stop firewalld //暂时关闭防火墙 systemctl disable firewalld //开机禁止启动 关闭selinux //不关…

【操作系统】实验二 作业调度模拟程序

一、目的和要求 1. 实验目的 &#xff08;1&#xff09;加深对作业调度算法的理解&#xff1b; &#xff08;2&#xff09;进行程序设计的训练。 2&#xff0e;实验要求 用高级语言编写一个或多个作业调度的模拟程序。 单道批处理系统的作业调度程序。作业一投入运行&#xff0…

Nuc972使用NandFlash时,uboot所需要的改动

先贴错误现象。 做工程&#xff0c;我发现&#xff0c;就应该里面记录下来&#xff0c;哪怕再简单&#xff0c;一两个月后&#xff0c;果断忘&#xff0c;最不能相信自己的脑子。不好使~~~~

手把手教你用Python爬虫煎蛋妹纸海量图片

我们的目标是用爬虫来干一件略污事情 最近听说煎蛋上有好多可爱的妹子&#xff0c;而且爬虫从妹子图抓起练手最好&#xff0c;毕竟动力大嘛。而且现在网络上的妹子很黄很暴力&#xff0c;一下接受太多容易营养不量&#xff0c;但是本着有人身体就比较好的套路&#xff0c;特意分…

chrome浏览器的跨域设置,前端修改跨域问题

原文&#xff1a;https://www.cnblogs.com/laden666666/p/5544572.html 做前后分离的webapp开发的时候&#xff0c;出于一些原因往往需要将浏览器设置成支持跨域的模式&#xff0c;好在chrome浏览器就是支持可跨域的设置&#xff0c;网上也有很多chrome跨域设置教程。但是新版本…

Server 2012 Hyper-v新功能之二:自动化支持技术

Server 2012 Hyper-v新功能之一&#xff1a;客户端 Hyper-V Windows PowerShell 是在 Windows Server 中执行自动化任务的脚本解决方案&#xff0c;新的适用于 Windows PowerShell 的 Hyper-V cmdlet 为 IT 专业人员提供了一种简单的方法&#xff0c;能够在 Windows Server 201…

SecureCRTSecureFX_HH_x64_7.0.0.326 crt部署项目到服务器

1.使用crt 2.输入服务器ip和账号 3.命令 cd 空格 /item/qd 回车进入到规定好的前端代码目录下 ls 查看目录下的文件 4.rm -rf 文件名称/或者目录名称&#xff08;空格删除多个、&#xff09; rm 空格 -rf 空格 *.zip 删除所有的zip rz 上传新的zip包 6。解压 unzip 空…

ant中的table和pagination表格分页结合使用 手写分页

表格部分 <a-table:row-selection"rowSelection" :columns"columns":data-source"data"class"components-table-demo-nested"change"onChangeTable":scroll"{ x:1600 ,y:500}":pagination"pagination&qu…

poj3692

最大独立集&#xff0c;把不认识的男女看成是有矛盾的&#xff0c;要选出一些互相没有矛盾的男女。 View Code #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std;#define maxn 205bool g[maxn][max…

在项目里交叉使用Swift和OC

From: http://blog.csdn.net/huangchentao/article/details/35278663 Swift and Objective-C in the Same Project 在项目里交叉使用Swift和OC Swift与OC的兼容性使得你可以在项目里使用SwiftOC的方式编写应用程序&#xff0c;称为混合匹配(mix and match)&#xff0c;用这种…

WireShark抓包,may be caused by ip checksum offload的解决办法

From: http://blog.csdn.net/yanjiee/article/details/8051494 今天在用WireShark抓包的时候&#xff0c;发现由本机发出去的包都是黑底红字&#xff0c;点进去看了一下发现都是报“may be caused by ip checksum offload”这样一个错误。 于是在网络上搜了一下关于Checksum o…

使用Dezender对zend加密后的php文件进行解密

在开发中需要修改一些php文件&#xff0c;部分是通过zend加密的&#xff0c;记事本打开之后是这样的&#xff1a; 此时需要使用Dezender进行解密&#xff0c;下载链接如下&#xff1a; Dezender.7z 下载后解压到C盘(路径不要带有中文)&#xff0c;如解压到其他位置&#xff0c;…