http://poj.org/problem?id=2420这个题是一道模拟退火题,但我用的是最小覆盖圆解决的;
这是我认为写得比较好的文章,在这里与大家分享。
这道题其实就是求一个最小外接圆圆心和半径。所求点即是圆心,距离就是半径。点集的最小外接圆,其实就是点集的最小圆覆盖,就是找一个最小的圆,将所有点覆盖掉。这道题的题意是求一个点,使得到点集的最远点距离最近,下边我用我的方式,不严谨的证明一下。先证明最小外接圆的圆心到其最远的点距离最近。可知最小外接圆上最少有两个点,如果是两个点,必然在一条直径上,否则就至少有三个点,且这三个点之间相对于圆心的夹角两两不超过180度。这点很好证明。如果不满足上述的情况,那么肯定能找到半个圆上没有任何点,
如上图所示,只要按照箭头方向移动,然后就可以缩小这个圆,直到满足这个条件为止。其实刚开始的那句话可以如此概括,点集的最小外切圆上,任意一条直径将圆分成两部分,要么两半圆上两部分上都有点,要么直径的两端都有点。先把解放在圆心上。这样的话,拥有最大长度的必定是那些在圆周上的点。然后我们看看移动解,能不能得到更优的结果,但是由于上述的性质,所以不管向哪里移动,总有一个圆周上的点到解的距离会变大,所以可知,圆心上的就是最优解。反过来证也差不多,所以我也不再赘述了。求最小外切圆目前看来最好的算法莫过于随机增量算法,其实就是增量算法,每次加一点进去,然后不断维护最小外切圆,但是裸的增量算法,最坏的时间复杂度是O(n^3)的,但是考虑到每次的更新发生的概率都较小,所以先给点集随机洗牌,这样可以做到概率上收敛于O(n)。(p.s:某些oj居然不能播种。。。但是不播种也无所谓了。。。反正都是伪随机)
这次就不上代码了,代码比较简单,主要是思维有点麻烦。


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 }