poj-1379 Run Away

来源:互联网 发布:贵州行知科技职业学校 编辑:程序博客网 时间:2024/06/07 07:30

题意:

给出一个矩形作为边界,内部有n个点;

求一个点到这些点距离的最小值最大;

n<=1000;


题解:

最小值最大——二分答案!

然而并不能做到= =

正解似乎是一个叫做Voronoi的神奇东西;

不过写个20k的精确算法不如秒个2k的骗分算法A掉它嘛;

这道题我写的就是模拟退火;

首先设中点为起点似乎比较美观吧;

然后就是普通的退火过程,照着百度百科扒一扒那几句话就好;

(1) 初始化:初始温度T(充分大),初始解状态S(是算法迭代的起点), 每个T值的迭代次数L
(2) 对k=1,……,L做第(3)至第6步:
(3) 产生新解S′
(4) 计算增量Δt′=C(S′)-C(S),其中C(S)为评价函数
(5) 若Δt′<0则接受S′作为新的当前解,否则以概率exp(-Δt′/(KT))接受S′作为新的当前解(k为波尔兹曼常数).
(6) 如果满足终止条件则输出当前解作为最优解,结束程序。
(7) T逐渐减少,且T->0,然后转第2步。

OI里终止条件一般视为T<EPS就好;

不卡精度不卡时,良心一A题;

感觉自己成为欧洲人了23333;


代码:


#include<math.h>#include<stdio.h>#include<string.h>#include<algorithm>#define N 11000using namespace std;const double EPS=1e-10;const double INF=1e100;struct Point{double x,y;Point(){}Point(double _,double __):x(_),y(__){}void read(){scanf("%lf%lf",&x,&y);}friend Point operator +(Point a,Point b){return Point(a.x+b.x,a.y+b.y);}friend Point operator -(Point a,Point b){return Point(a.x-b.x,a.y-b.y);}friend double operator *(Point a,Point b){return a.x*b.x+a.y*b.y;}friend double dis2(Point a,Point b){return (a-b)*(a-b);}}p[N];double X,Y;int n;double drand(){return rand()%10000/10000.0;}double calc(Point a){double ret=INF;for(int i=1;i<=n;i++){ret=min(ret,dis2(a,p[i]));}return -ret;}void slove(Point& ans,double T){Point next,dt;double E,nE,dE;while(T>EPS){dt=Point((drand()*2-1.0)*T,(drand()*2-1.0)*T);next=ans+dt;next.x=min(X,max(0.0,next.x)),next.y=min(Y,max(0.0,next.y));nE=calc(next);dE=nE-E;if(dE<0||drand()<exp(-dE/T))ans=next,E=nE;T*=0.99140142;}}int main(){srand(140142);int c,T,m,i,j,k;Point ans;scanf("%d",&T);for(c=1;c<=T;c++){scanf("%lf%lf%d",&X,&Y,&n);for(i=1;i<=n;i++)p[i].read();ans=Point(X/2,Y/2);slove(ans,max(X,Y)/2);printf("The safest point is (%.1lf, %.1lf).\n",ans.x,ans.y);}return 0;}



0 0
原创粉丝点击