hdu3932 最小圓覆蓋-模擬退火實現-3+
阿新 • • 發佈:2018-11-01
http://acm.hdu.edu.cn/showproblem.php?pid=3932
題意:給一堆點,求一個點到這些點的最遠距離最小。。。精度0.1即可
分析:
此題本來是最小圓覆蓋的模板題。。。我一開始就想到費馬點的模擬退火去了。。花了一個下午沒寫出來。。。。
最開始是用4個方向的搜尋判斷減小步長的方式,後來改到8個方向還是不行,精度都調到10e-9都不行。。。最後改成對當前點周圍很多點(貌似用了60個)進行判斷精度只需要到0.1就過了。。。表示本人無法解釋原因。。。
以後不敢寫模擬退火了。。上次福州現場賽調了那麼久的精度險過啊。。。。。有木有!!!!!
程式碼:
#include<iostream> #include<cmath> using namespace std; const double pi = 3.141592654; const int N=1010; struct point { double x, y; } p[N], mn, mx, mid, mid1; int n, X, Y; double ans, ans1; double dis(point a, point b) { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); } void cal(double x, double y) { int i, j; double mx=0, tmp; point tp; tp.x = x; tp.y = y; for(i=0; i<n; i++) { tmp = dis(p[i], tp); if(tmp>mx) mx = tmp; } if(ans1>mx) { ans1 = mx; mid1 = tp; } } int main() { int i, j, k; double width; while(scanf("%d%d%d", &X, &Y, &n)!=EOF) { mn.x = mn.y = 0x7fffffff; mx.x = mx.y = 0; for(i=0; i<n; i++) { scanf("%lf%lf", &p[i].x, &p[i].y); if(p[i].x<mn.x) mn.x = p[i].x; if(p[i].y<mn.y) mn.y = p[i].y; if(p[i].x>mx.x) mx.x = p[i].x; if(p[i].y>mx.y) mx.y = p[i].y; } mid.x = (mn.x+mx.x)/2; mid.y = (mn.y+mx.y)/2; mid1 = mid; width = mx.x; if(mx.y>width) width = mx.y; ans1 = 0; for(i=0; i<n; i++) { if(dis(mid, p[i])>ans1) ans1 = dis(mid, p[i]); } ans = ans1; double ii; while(1) { /* cal(mid.x-width, mid.y); //判斷4個,8個方向不行。。即使精度調到10e-9 cal(mid.x+width, mid.y); cal(mid.x, mid.y-width); cal(mid.x, mid.y+width); cal(mid.x-width, mid.y-width); cal(mid.x-width, mid.y+width); cal(mid.x+width, mid.y-width); cal(mid.x+width, mid.y+width); */ for(ii=0; ii<=2*pi; ii+=0.1) //旋轉對很多個點進行判斷。。 { cal(mid.x+width*cos(ii), mid.y+width*sin(ii)); } if(ans-ans1<0.1 && width<0.001) break; if(ans1<ans) { ans = ans1; mid = mid1; } else width *= 0.5; } printf("(%.1lf,%.1lf).\n", mid.x, mid.y); printf("%.1lf\n", sqrt(ans)); } return 0; }