题意:给定n个点和范围,在范围内找到一个点,使得n个点到这个点的最小距离最大
模拟退火法
模拟退火的过程
1 找到这些点所在的范围,用两个点框定(代码中e1,e2两个点)
2 在这个范围内生成NUM个点(NUM自定)
3 对于每个生成的点i,在其周围生成NUM个点,一旦有点优于i,则替换。
4 缩小范围D,若D<精度,退出,否则执行 3
模拟退火法
模拟退火的过程
1 找到这些点所在的范围,用两个点框定(代码中e1,e2两个点)
2 在这个范围内生成NUM个点(NUM自定)
3 对于每个生成的点i,在其周围生成NUM个点,一旦有点优于i,则替换。
4 缩小范围D,若D<精度,退出,否则执行 3
5 遍历所有NUM个点,找到val的最大值
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-6;
const double inf=1e10;
const int n_max=1005;
const int num=20;
const int RAD=10005;
double X,Y;
int n;
struct point
{
double x,y,v;
point(){}
point(double tx,double ty)
{
x=tx;
y=ty;
}
}p[n_max],may[num];
double randone()
{
return (rand()%RAD+1)/(double)(RAD);
}
point point_rand(point a,point b)
{
double x=a.x+(b.x-a.x)*randone();
double y=a.y+(b.y-a.y)*randone();
return point(x,y);
}
double dist(point a,point b)
{
return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}
double getv(point a)
{
int i;
double mi=inf;
for(i=0;i<n;i++)
{
mi=min(mi,dist(a,p[i]));
}
return mi;
}
void monisrand(double D)
{
may[0]=point(0,0);
may[1]=point(X,Y);
may[2]=point(X,0);
may[3]=point(0,Y);
int i,j;
for(i=4;i<num;i++)
{
may[i]=point_rand(may[0],may[1]);
}
for(i=0;i<num;i++)
{
may[i].v=getv(may[i]);
}
point temp,t1,t2;
while(D>eps)
{
for(i=0;i<num;i++)
{
for(j=0;j<num;j++)
{
t1=point(max(0.0,may[i].x-D),max(0.0,may[i].y-D));
t2=point(min(X,may[i].x+D),min(Y,may[i].y+D));
temp=point_rand(t1,t2);
temp.v=getv(temp);
if(temp.v>may[i].v)
{
may[i]=temp;
}
}
}
D*=0.9;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lf%lf%d",&X,&Y,&n);
int i;
for(i=0;i<n;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
}
monisrand(max(X,Y));
point ans;
ans.v=0;
for(i=0;i<num;i++)
{
if(may[i].v>ans.v)
{
ans=may[i];
}
}
printf("The safest point is (%.1lf, %.1lf).\n",ans.x,ans.y);
}
return 0;
}