最近研究了下模拟退火,首先戳这里>_<顾研08年集训队论文,讲的非常详细
首先随机20个点作为候选解,以此扩展来确定距离工厂最近的点的最远的距离是多少。但是有需要注意到扩展点在边界的情况,因为边界是圆所以很难继续扩展,如论文中提到的两种情况。1.是两工厂垂直平分线与边界交点2.一个工厂的圆与边界相切。单独判断即可。
其中有个很蛋疼的地方,我之前距离用了很多次sqrt,T成狗,比较距离时只需比较距离平方,答案最后再开根即可
代码:https://github.com/mlz000/Ural/blob/master/1502(%E6%A8%A1%E6%8B%9F%E9%80%80%E7%81%AB).cpp
#include<iostream>//模拟退火
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<algorithm>
using namespace std;
#define sqr(x) ((x)*(x))
const int N=305;
const double Pi=acos(-1.0),eps=1e-9,inf=1e10;
int n;
double r;
struct Point{
double x,y,d;
}a[N],b[25],tmp,tmp1,tmp2;
double dis(double x1,double y1,double x2,double y2){
return sqr(x1-x2)+sqr(y1-y2);
}
int dcmp(double x){
if(x<eps) return -1;
return x>eps;
}
void calc(Point &p){
p.d=inf;
if(dcmp(sqr(p.x)+sqr(p.y)-r*r)>0){
p.d=0;
return;
}
for(int i=1;i<=n;++i) p.d=min(p.d,dis(p.x,p.y,a[i].x,a[i].y));
}
int main(){
while(~scanf("%d%lf",&n,&r)){
for(int i=1;i<=n;++i) scanf("%lf%lf",&a[i].x,&a[i].y);
for(int i=1;i<=20;++i){
double len=(rand()%100)/100.0*r;
double ang=(rand()%100)/100.0*2.0*Pi;
b[i].x=len*cos(ang);
b[i].y=len*sin(ang);
calc(b[i]);
}
double delta=r*2/sqrt(20.0);
for(;delta>1e-7;delta*=0.6)
for(int i=1;i<=20;++i)
for(int j=1;j<=30;++j){
double ang=(rand()%100)/100.0*2.0*Pi;
tmp.x=b[i].x+delta*cos(ang);
tmp.y=b[i].y+delta*sin(ang);
calc(tmp);
if(tmp.d>b[i].d) b[i]=tmp;
}
double ans=0.0;
for(int i=1;i<=20;++i) ans=max(ans,b[i].d);
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j){
double A,B,C,d,s,xx,yy;
A=2*(a[i].x-a[j].x),B=2*(a[i].y-a[j].y),C=sqr(a[j].x)+sqr(a[j].y)-sqr(a[i].x)-sqr(a[i].y);
s=A*A+B*B;
d=r*r*s-sqr(C);//d=d*(A^2+B^2)
if(d+eps<0) continue;
if(d<eps) d=0;
else d=sqrt(d);
if(s==0) continue;
xx=-A*C;
yy=-B*C;
tmp1.x=(xx+B*d)/s,tmp1.y=(yy-A*d)/s;
tmp2.x=(xx-B*d)/s,tmp2.y=(yy+A*d)/s;
calc(tmp1);
ans=max(ans,tmp1.d);
calc(tmp2);
ans=max(ans,tmp2.d);
}
for(int i=1;i<=n;++i){
double d=sqrt(sqr(a[i].x)+sqr(a[i].y));
if(dcmp(d)<=0) continue;
tmp.x=a[i].x*r/d;
tmp.y=a[i].y*r/d;
calc(tmp);
ans=max(ans,tmp.d);
tmp.x=-tmp.x;
tmp.y=-tmp.y;
calc(tmp);
ans=max(ans,tmp.d);
}
printf("%.8lf\n",sqrt(ans));
}
return 0;
}
Ural 1520 Empire Strikes Back(模拟退火),布布扣,bubuko.com
Ural 1520 Empire Strikes Back(模拟退火)
原文地址:http://blog.csdn.net/mlzmlz95/article/details/38358127