UVA10228 模拟退火
题目链接:
https://www.luogu.org/problem/UVA10228
一眼看。很明显嘛,裸的模拟退火
什么?你不知道什么是模拟退火?出门请右转 https://www.cnblogs.com/btcadmire123A/articles/11248754.html
如果想要更好的游戏体验, https://www.cnblogs.com/flashhu/p/8884132.html;
所以::为什么是模拟退火的说?
看官请看:
给定一个N边形所有顶点坐标x,y,求其费马点到所有顶点距离和。费马点是指到多边形所有顶点距离和最小的点。
某大神说:我会计算平面几何+三分,复杂度优秀。 请您左转至题库切了他。
在这里我提供的是随机化算法(模拟退火)。
在我看来,退火明显比爬山算法好(虽然都属玄学),因为他有更大几率获得全局最优解,而非局部。
当然操作还是分为Calc与SA(Simulate Anneal)的啦。
此时寻找的解是此时的“费马点”到所有顶点的坐标距离(二维距离,非曼哈顿距离)。
calc操作表示此时解的费马距离(口胡定义,莫要见怪)并实时更新。
SA操作照样负责骚找随机解并judge更新否?
代码若下:
#include<cstring> #include<cmath> #include<cstdio> #include<cctype> #include<ctime> #include<algorithm> #include<iostream> using namespace std; #define maxn 10050 int x[1005],y[1005],n,T; double ansx,ansy,ans; int read(); double calc(double a,double b); void SA(); void work(); int main(){ T=read(); while(T--){ n=read(); for(int i=1;i<=n;i++) x[i]=read(),y[i]=read(); ansx=ansy=0;ans=calc(0,0); work(); cout<<(int)(ans+0.5)<<endl; if(T) cout<<endl; } } int read(){ int ans=0,f=1;char t; while(t<'0'||t>'9') {if(t=='-') f=-1;t=getchar();} while(t>='0'&&t<='9') ans=ans*10+t-'0',t=getchar(); return ans*f; } double calc(double a,double b){ double ret=0; for(int i=1;i<=n;i++) ret+=sqrt((x[i]-a)*(x[i]-a)+(y[i]-b)*(y[i]-b)); return ret; } void SA(){ double x=ansx,y=ansy; for(double Temp=50001;Temp>=0.00000001;Temp*=0.98){ double nx=Temp*(rand()*2-RAND_MAX)+x; double ny=Temp*(rand()*2-RAND_MAX)+y; double nans=calc(nx,ny); double bet=nans-ans; if(bet<0) ans=nans,x=ansx=nx,y=ansy=ny; else if(exp(-bet/Temp)*RAND_MAX>rand()) x=nx,y=ny; } } void work(){ for(int i=1;i<=15;i++) SA(); }
我才不会告诉你我没有UVA账号,不能提交。 我也不知道它能不能AC。
Cogito ergo sum