模拟退火
我觉得这是个 useless 的算法,只能说正解肯定和这算法毫无关系,你用这算法也别想拿满分,顶多是个不会做的题浪费你时间去赌这么些运气,而且是真的看脸。。。
先看张 oi-wiki 的图:
简单点想:
我们模拟分子运动的过程,随机选取答案,每次令答案跳跃一个距离,也就是随机移动,温度越高,跳的距离就可能越 浮躁 也就是大,温度越低,随机移动的距离就会慢慢减小,不断更新答案得到 “可能” 的最优解。
显然你开始的温度越高你就越可能得到答案,但是相对应的是时间的代价。
算法流程:
-
固定一个起始的 /(t/) 代表跳跃的种子,也就是温度 ,还有一个系数 /(down/) ,一般令 /(down = 0.996~0.998/) 吧, /(t/) 可以取一个不大不小的数。
-
每次通过这个 /(t/) 随机得到一个答案,并估价这个答案,也就是检查当前答案和之前最优解的优劣性。
- 若当前更优,那么直接选用他。
- 若当前更劣,那么假设代价劣了 /(d/) ,就以 /(e^{/frac{d}{t}}/) 的概率选用这个答案,
其实就是玄学。
-
$ t /times = down$
-
若 /(t/) 无限接近于 /(0/) ,结束退火。
然后就是有一个小优化,为了防止TLE,可以直接判断当前运行的时间,也就是 while((double)clock() / CLOCKS_PER_SEC <= 0.997)(以题目时限自定义的时间)
然后如果不超时就继续退火,否则结束程序。
PS:模拟退火看脸,所以如果觉得分不够可以申请重测,会有惊喜也会有惊吓/qd
这里就向量分解一下,然后直接按刚才的流程走就好了,注意 /(e^{x}/) 可以用 /(exp(x)/) 来得到。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(f)x=-x;
}
template <typename T,typename ...Args>
inline void read(T &tmp,Args &...tmps){read(tmp);read(tmps...);}
const double down = 0.996;
const int N = 2005;
const double eps = 1e-15;
int n;
struct qwq{
int x,y,w;
}a[N];
mt19937 rnd(time(0));
double sx,sy,sw;
double energy(double x,double y){//代价
double res = 0,dx ,dy;
rep(i,1,n){
dx = x - a[i].x;
dy = y - a[i].y;
res += sqrt(dx * dx + dy * dy) * a[i].w;
}
return res;
}
void tuihuo(){
double t = 3000;
while(t > eps){
double ex = sx + (rand() * 2 - RAND_MAX) * t;
double ey = sy + (rand() * 2 - RAND_MAX) * t;
double ew = energy(ex,ey);
double d = ew - sw;
if(d < 0)sx = ex,sy = ey,sw = ew;//优
else if(exp(-d / t) * RAND_MAX > rand())sx = ex,sy = ey;//劣则概率更新答案
t *= down;
}
}
void solve(){
rep(i,1,4)tuihuo();
}
signed main(){
srand(time(0));
read(n);
rep(i,1,n)read(a[i].x,a[i].y,a[i].w),sx += a[i].x,sy += a[i].y;
sx /= n;sy /= n;sw = energy(sx,sy);
solve();
printf("%.3lf %.3lf/n",sx,sy);
}
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/288254.html