ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模拟退火

2022-09-08 12:35:20  阅读:233  来源: 互联网

标签:sy ch read double sx 模拟退火 答案


模拟退火

我觉得这是个 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);
}

标签:sy,ch,read,double,sx,模拟退火,答案
来源: https://www.cnblogs.com/wsxxs/p/16669002.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有