这个题是一道模拟退火题,但我用的是最小覆盖圆解决的;

这是我认为写得比较好的文章,在这里与大家分享。

这道题其实就是求一个最小外接圆圆心和半径。所求点即是圆心,距离就是半径。点集的最小外接圆,其实就是点集的最小圆覆盖,就是找一个最小的圆,将所有点覆盖掉。这道题的题意是求一个点,使得到点集的最远点距离最近,下边我用我的方式,不严谨的证明一下。先证明最小外接圆的圆心到其最远的点距离最近。可知最小外接圆上最少有两个点,如果是两个点,必然在一条直径上,否则就至少有三个点,且这三个点之间相对于圆心的夹角两两不超过180度。这点很好证明。如果不满足上述的情况,那么肯定能找到半个圆上没有任何点,


如上图所示,只要按照箭头方向移动,然后就可以缩小这个圆,直到满足这个条件为止。其实刚开始的那句话可以如此概括,点集的最小外切圆上,任意一条直径将圆分成两部分,要么两半圆上两部分上都有点,要么直径的两端都有点。先把解放在圆心上。这样的话,拥有最大长度的必定是那些在圆周上的点。然后我们看看移动解,能不能得到更优的结果,但是由于上述的性质,所以不管向哪里移动,总有一个圆周上的点到解的距离会变大,所以可知,圆心上的就是最优解。反过来证也差不多,所以我也不再赘述了。求最小外切圆目前看来最好的算法莫过于随机增量算法,其实就是增量算法,每次加一点进去,然后不断维护最小外切圆,但是裸的增量算法,最坏的时间复杂度是O(n^3)的,但是考虑到每次的更新发生的概率都较小,所以先给点集随机洗牌,这样可以做到概率上收敛于O(n)。(p.s:某些oj居然不能播种。。。但是不播种也无所谓了。。。反正都是伪随机)

 这次就不上代码了,代码比较简单,主要是思维有点麻烦。

 

最小外接多边形算法java 最小外接圆的定义_i++

最小外接多边形算法java 最小外接圆的定义_#include_02

View Code

1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const double PI = acos( -1.0 );
 7 class Point
 8 {
 9 public:
10        double  x,y;      
11 };
12 Point point[1024],mid,mincoorde,maxcoorde,midstep;
13 double ans , ansmin , X ,Y ,R;
14 int n;
15 double Distance( Point a, Point b )
16 {
17     return sqrt(( a.x - b.x )*( a.x - b.x ) + ( a.y - b.y )*( a.y - b.y ));
18 }       
19 void Solve( double x, double y )
20 {
21     Point  tp;
22     double max = 0 ;
23     tp.x = x ; tp.y = y;  
24     for( int i = 0; i < n ; i ++ )
25     {
26          max += Distance( tp , point[i] );     
27     }
28     if( max < ans )
29     {
30         ans = max;
31         midstep = tp;  
32     }   
33 }
34 int main(  )
35 {
36    while( scanf( "%d",&n )==1 )
37    {
38        maxcoorde.x = maxcoorde.y = 0;
39        mincoorde.x = mincoorde.y = 10000;
40        for( int i = 0 ; i < n ; i++ )
41        {
42             scanf( "%lf %lf",&point[i].x , &point[i].y );
43             if( point[i].x > maxcoorde.x ) maxcoorde.x = point[i].x;
44             if( point[i].y > maxcoorde.y ) maxcoorde.y = point[i].y;
45             if( point[i].x < mincoorde.x ) mincoorde.x = point[i].x;
46             if( point[i].y < mincoorde.y ) mincoorde.y = point[i].y;    
47        }       
48        mid.x = ( maxcoorde.x + mincoorde.x )/2.0;
49        mid.y = ( maxcoorde.y + mincoorde.y )/2.0;
50        R=sqrt((maxcoorde.x-mincoorde.x)*(maxcoorde.y-mincoorde.y) + (maxcoorde.x-mincoorde.x)*(maxcoorde.y-mincoorde.y))/2.0;
51        ans = 0;
52        for( int i = 0; i < n; i++ )
53        {
54           ans += Distance( mid , point[i] );
55        }
56        ansmin = ans;
57        while( 1 )
58        {
59             for( double i = 0; i <= 2*PI; i += 0.1 ) 
60             {
61                Solve( mid.x + R*sin( i ) , mid.y + R*cos( i ) );
62             } 
63             if( ( ansmin - ans ) < 0.1 && R < 0.01 ) break;
64             if( ansmin > ans )
65             {
66                ansmin = ans;
67                mid = midstep;    
68             } 
69             else R*=0.7;      
70        }
71     //   printf( "(%.1lf,%.1lf).\n",mid.x, mid.y );
72        printf( "%.lf\n",ansmin);
73    }
74    return 0;    
75 }