POJ2069 最小球覆蓋 幾何法和退火法
阿新 • • 發佈:2017-05-08
集中 names ios .com .html 一個 i++ blog 穩定
對這種問題不熟悉的讀者 可以先去看一看最小圓覆蓋的問題 ZOJ1450
現在我們來看最小球覆蓋問題POJ2069 題目很裸,給30個點 求能覆蓋所有點的最小球的半徑。
先給出以下幾個事實:
1.對於一個點,球心就是這個點且半徑無窮小。
2.對於兩個點,球心是兩個點線段的中點,半徑就是線段長度的一半。
3.對於三個點,三個點構成的平面必為球的大圓,所以球心是三角形的外心,半徑就是球心到某個點的距離。
4.對於四個點,若四個點共面則轉化到3,只需考慮某三個點的情況,若四點不共面,四面體可以唯一確定一個外接球。
5.對於五個及以上點,其最小球必為其中某4個點的外接球(假設不全共面)。
C(30,4)是可以接受的復雜度。在編程實現的時候,碰到不在球內的點,就讓它成為球面上的點,期望復雜度為O(n)。
-----------------------------------------------------------------------------------------------------------------------------------------------
以上我們給出了一般的幾何解法,但是求三角形外心和四面體的外界球,方程很復雜,代碼量也很大,有沒有簡單的方法呢?
我們根據以上5個事實,可以知道所謂最小球的球心,它必然處於一個穩定態,也就是與它距離最遠的點最多有4個且等距離。
於是,我們首先任選一個點作為球心,並找到點集中與它距離最遠的點,我們讓球心靠近最遠的點,不斷重復此過程,就可以讓球心達到穩定態了!此時我們就找到了最小球。
1 #include <iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const double eps=1e-7; 8 struct point3D 9 { 10 double x,y,z; 11 } data[35]; 12 int n; 13 double dis(point3D a,point3D b)View Code14 { 15 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); 16 } 17 double solve() 18 { 19 double step=100,ans=1e30,mt; 20 point3D z; 21 z.x=z.y=z.z=0; 22 int s=0; 23 while(step>eps) 24 { 25 for(int i=0; i<n; i++) 26 if(dis(z,data[s])<dis(z,data[i])) s=i; 27 mt=dis(z,data[s]); 28 ans=min(ans,mt); 29 z.x+=(data[s].x-z.x)/mt*step; 30 z.y+=(data[s].y-z.y)/mt*step; 31 z.z+=(data[s].z-z.z)/mt*step; 32 step*=0.98; 33 } 34 return ans; 35 } 36 int main() 37 { // freopen("t.txt","r",stdin); 38 double ans; 39 while(~scanf("%d",&n),n) 40 { 41 for(int i=0; i<n; i++) 42 scanf("%lf%lf%lf",&data[i].x,&data[i].y,&data[i].z); 43 ans=solve(); 44 printf("%.5f\n",ans); 45 } 46 return 0; 47 }
POJ2069 最小球覆蓋 幾何法和退火法