您的位置:首页 > 其它

hdu3932 最小圆覆盖-模拟退火实现-3+

2011-08-24 10:39 253 查看
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
, 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: