生活随笔
收集整理的這篇文章主要介紹了
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?
#include?<iostream>??#include?<cstring>??#include?<cstdlib>??#include?<cstdio>??#include?<queue>??#include?<cmath>??#include?<algorithm>????#define?LL?long?long??#define?PI?(acos(-1.0))??#define?EPS?(1e-10)????using?namespace?std;????struct?P??{??????double?x,y,a;??}p[1100],cp[1100];????struct?L??{??????P?p1,p2;??}?line[50];????double?X_Mul(P?a1,P?a2,P?b1,P?b2)??{??????P?v1?=?{a2.x-a1.x,a2.y-a1.y},v2?=?{b2.x-b1.x,b2.y-b1.y};??????return?v1.x*v2.y?-?v1.y*v2.x;??}????double?Cal_Point_Dis(P?p1,P?p2)??{??????return?sqrt((p1.x-p2.x)*(p1.x-p2.x)?+?(p1.y-p2.y)*(p1.y-p2.y));??}????double?Cal_Point_Dis_Pow_2(P?p1,P?p2)??{??????return?(p1.x-p2.x)*(p1.x-p2.x)?+?(p1.y-p2.y)*(p1.y-p2.y);??}????P?Cal_Segment_Cross_Point(P?a1,P?a2,P?b1,P?b2)??{??????double?t?=?X_Mul(b1,b2,b1,a1)?/?X_Mul(a1,a2,b1,b2);??????P?cp?=?{a1.x+(a2.x-a1.x)*t,a1.y+(a2.y-a1.y)*t};??????return?cp;??}????//規范相交??bool?Is_Seg_Cross_Without_Point(P?a1,P?a2,P?b1,P?b2)??{??????double?xm1?=?X_Mul(a1,a2,a1,b1);??????double?xm2?=?X_Mul(a1,a2,a1,b2);??????double?xm3?=?X_Mul(b1,b2,b1,a1);??????double?xm4?=?X_Mul(b1,b2,b1,a2);????????return?(xm1*xm2?<?(-EPS)?&&?xm3*xm4?<?(-EPS));??}????//向量ab與X軸正方向的夾角??double?Cal_Angle(P?t,P?p)??{??????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)));??}????//計算?∠b2.a.b1?的大小??double?Cal_Angle_Three_Point(P?a,P?b1,P?b2)??{??????double?l1?=?Cal_Point_Dis_Pow_2(b1,a);??????double?l2?=?Cal_Point_Dis_Pow_2(b2,a);??????double?l3?=?Cal_Point_Dis_Pow_2(b1,b2);????????return?acos(?(l1+l2-l3)/(2*sqrt(l1*l2))?);??}????bool?cmp_angle(P?p1,P?p2)??{??????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)???);??}????//p為點集??應該保證至少有三點不共線??//n?為點集大小??//返回值為凸包上點集上的大小??//凸包上的點存儲在cp中??int?Creat_Convex_Hull(P?*p,int?n)??{??????int?i,top;??????P?re;?//re?為建立極角排序時的參考點??下左點????????for(re?=?p[0],i?=?1;?i?<?n;?++i)??????{??????????if(re.y?>?p[i].y?||?(fabs(re.y-p[i].y)?<?EPS?&&?re.x?>?p[i].x))??????????????re?=?p[i];??????}????????for(i?=?0;?i?<?n;?++i)??????{??????????if(p[i].x?==?re.x?&&?p[i].y?==?re.y)??????????{??????????????p[i].a?=?-2;??????????}??????????else?p[i].a?=?Cal_Angle(re,p[i]);??????}????????sort(p,p+n,cmp_angle);????????top?=0?;??????cp[top++]?=?p[0];??????cp[top++]?=?p[1];????????for(i?=?2?;?i?<?n;)??????{??????????if(top?<?2?||?X_Mul(cp[top-2],cp[top-1],cp[top-2],p[i])?>?EPS)??????????{??????????????cp[top++]?=?p[i++];??????????}??????????????????????else??????????{??????????????--top;??????????}??????}????????return?top;??}????bool?Is_Seg_Parallel(P?a1,P?a2,P?b1,P?b2)??{??????double?xm1?=?X_Mul(a1,a2,a1,b1);??????double?xm2?=?X_Mul(a1,a2,a1,b2);????????return?(fabs(xm1)?<?EPS?&&?fabs(xm2)?<?EPS);??}????bool?Point_In_Seg(P?m,P?a1,P?a2)??{??????double?l1?=?Cal_Point_Dis(m,a1);??????double?l2?=?Cal_Point_Dis(m,a2);??????double?l3?=?Cal_Point_Dis(a1,a2);????????return?(fabs(l1+l2-l3)?<?EPS);??}????//計算三角形外接圓圓心??P?Cal_Triangle_Circumcircle_Center(P?a,P?b,P?c)??{????????P?mp1?=?{(b.x+a.x)/2,(b.y+a.y)/2},mp2?=?{(b.x+c.x)/2,(b.y+c.y)/2};??????P?v1?=?{a.y-b.y,b.x-a.x},v2?=?{c.y-b.y,b.x-c.x};????????P?p1?=?{mp1.x+v1.x,mp1.y+v1.y},p2?=?{mp2.x+v2.x,mp2.y+v2.y};????????return?Cal_Segment_Cross_Point(mp1,p1,mp2,p2);??}????bool?Is_Acute_Triangle(P?p1,P?p2,P?p3)??{??????//三點共線??????if(fabs(X_Mul(p1,p2,p1,p3))?<?EPS)??????{??????????return?false;??????}????????double?a?=?Cal_Angle_Three_Point(p1,p2,p3);??????if(a?>?PI?||?fabs(a-PI)?<?EPS)??????{??????????return?false;??????}??????a?=?Cal_Angle_Three_Point(p2,p1,p3);??????if(a?>?PI?||?fabs(a-PI)?<?EPS)??????{??????????return?false;??????}??????a?=?Cal_Angle_Three_Point(p3,p1,p2);??????if(a?>?PI?||?fabs(a-PI)?<?EPS)??????{??????????return?false;??????}??????return?true;??}????bool?Is_In_Circle(P?center,double?rad,P?p)??{??????double?dis?=?Cal_Point_Dis(center,p);??????return?(dis?<?rad?||?fabs(dis-rad)?<?EPS);??}????P?Cal_Seg_Mid_Point(P?p2,P?p1)??{??????P?mp?=?{(p2.x+p1.x)/2,(p1.y+p2.y)/2};??????return?mp;??}????void?Cal_Min_Circle(P?*p,int?n)??{??????if(n?==?0)??????????return?;??????if(n?==?1)??????{??????????printf("%.2lf?%.2lf?%.2lf\n",p[0].x,p[0].y,0.00);??????????return?;??????}??????if(n?==?2)??????{??????????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);??????????return?;??????}????????P?center?=?Cal_Seg_Mid_Point(p[0],p[1]),tc1;????????double?dis,temp,rad?=?Cal_Point_Dis(p[0],center),tra1;??????int?i,site,a?=?0,b?=?1,c?=?2,d,s1,s2,tp;????????for(dis?=?-1,site?=?0,i?=?0;?i?<?n;?++i)??????{??????????temp?=?Cal_Point_Dis(center,p[i]);??????????if(temp?>?dis)??????????{??????????????dis?=?temp;??????????????site?=?i;??????????}??????}????????while(?Is_In_Circle(center,rad,p[site])?==?false?)??????{??????????d?=?site;?????????//?printf("a?=?%d?b?=?%d?c?=?%d?d?=?%d\n",a,b,c,d);????????????//printf("x?=?%.2lf??y?=?%.2lf\n",center.x,center.y);???????????//?printf("rad?=?%.2lf\n\n",rad);?????????//?getchar();????????????double?l1?=?Cal_Point_Dis(p[a],p[d]);??????????double?l2?=?Cal_Point_Dis(p[b],p[d]);??????????double?l3?=?Cal_Point_Dis(p[c],p[d]);????????????if((l1?>?l2?||?fabs(l1-l2)?<?EPS)?&&?(l1?>?l3?||?fabs(l1-l3)?<?EPS))??????????{??????????????s1?=?a,s2?=?d,tp?=?b;??????????}??????????else?if((l2?>?l1?||?fabs(l1-l2)?<?EPS)?&&?(l2?>?l3?||?fabs(l2-l3)?<?EPS))??????????{??????????????s1?=?b,s2?=?d,tp?=?c;??????????}??????????else??????????{??????????????s1?=?c,s2?=?d,tp?=?a;??????????}????????????center?=?Cal_Seg_Mid_Point(p[s1],p[s2]);??????????rad?=?Cal_Point_Dis(center,p[s1]);????????????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?)??????????{??????????????center?=?Cal_Triangle_Circumcircle_Center(p[a],p[c],p[d]);??????????????rad?=?Cal_Point_Dis(p[d],center);??????????????s1?=?a,s2?=?c,tp?=?d;????????????????if(Is_In_Circle(center,rad,p[b])?==?false)??????????????{??????????????????center?=?Cal_Triangle_Circumcircle_Center(p[a],p[b],p[d]);??????????????????rad?=?Cal_Point_Dis(p[d],center);??????????????????s1?=?a,s2?=?b,tp?=?d;??????????????}??????????????else??????????????{??????????????????tc1?=?Cal_Triangle_Circumcircle_Center(p[a],p[b],p[d]);??????????????????tra1?=?Cal_Point_Dis(p[d],tc1);????????????????????if(tra1?<?rad?&&?Is_In_Circle(tc1,tra1,p[c]))??????????????????{??????????????????????rad?=?tra1,center?=?tc1;??????????????????????s1?=?a,s2?=?b,tp?=?d;??????????????????}??????????????}????????????????if(Is_In_Circle(center,rad,p[c])?==?false)??????????????{??????????????????center?=?Cal_Triangle_Circumcircle_Center(p[c],p[b],p[d]);??????????????????rad?=?Cal_Point_Dis(center,p[d]);??????????????????s1?=?c,s2?=?b,tp?=?d;??????????????}??????????????else??????????????{??????????????????tc1?=?Cal_Triangle_Circumcircle_Center(p[c],p[b],p[d]);??????????????????tra1?=?Cal_Point_Dis(p[d],tc1);??????????????????if(tra1?<?rad?&&?Is_In_Circle(tc1,tra1,p[a]))??????????????????{??????????????????????rad?=?tra1,center?=?tc1;??????????????????????s1?=?b,s2?=?c,tp?=?d;??????????????????}??????????????}??????????}????????????a?=?s1,b?=?s2,c?=?tp;????????????for(dis?=?-1,site?=?0,i?=?0;i?<?n;?++i)??????????{??????????????temp?=?Cal_Point_Dis(center,p[i]);??????????????if(temp?>?dis)??????????????{??????????????????dis?=?temp;??????????????????site?=?i;??????????????}??????????}??????}??????printf("%.2f?%.2f?%.2f\n",center.x,center.y,rad);??}????int?main()??{??????int?i,n;??????while(scanf("%d",&n)?&&?n)??????{??????????for(i?=?0;i?<?n;?++i)??????????{??????????????scanf("%lf?%lf",&p[i].x,&p[i].y);??????????}??????????Cal_Min_Circle(p,n);??????}??}?
?
總結
以上是生活随笔為你收集整理的ZOJ 1450 Minimal Circle 点集的最小圆覆盖的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。