1. 程式人生 > >POJ2069 最小球覆蓋 幾何法和退火法

POJ2069 最小球覆蓋 幾何法和退火法

集中 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)  
14 { 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 }
View Code

POJ2069 最小球覆蓋 幾何法和退火法